none
Mobile Services - Exception - The operation has been updated and cannot be updated again RRS feed

  • Question

  • Can someone explain what exactly would cause this exception to be thrown?  I have received this and I am not sure what is causing it.

    The operation has been updated and cannot be updated again

    private async Task TryUpdateOperation(MobileServiceTableOperationError error, JObject item)
            {
                if (!await this.opQueue.UpdateAsync(error.Id, error.OperationVersion, item))
                {
                    throw new InvalidOperationException("The operation has been updated and cannot be updated again");
                }
    
                // delete errors for updated operation
                await this.Store.DeleteAsync(MobileServiceLocalSystemTables.SyncErrors, error.Id);
            }


    Tuesday, July 12, 2016 7:28 PM

Answers

  • Yes, you should definitely suspend the sync if the user is editing the item. Aside from the exception that you're seeing, you could end up with conflicting edits and the potential for losing server changes. For instance, if the user is updating record A and a sync is happening at the same time, and record A has been updated on the server, the user will not see the change. While it's possible to code around by attaching a listener to pull events, it's pretty complex and error prone.

    A more predictable user experience is to manually refresh before the user edits the record, and suspend automatic syncing. This will also prevent the exception you're seeing.

    Wednesday, July 13, 2016 9:18 PM
    Moderator

All replies

  • What is the scenario where this exception is occurring?  It's possible that a sync operation is in progress and you are trying to concurrently update an item that is already in the sync queue. To prevent this, you should await the sync operation before doing the update operation. If you're using await throughout your code, this shouldn't block any UI.
    Tuesday, July 12, 2016 10:15 PM
    Moderator
  • We basically have one page in the app to create/update widgets and we also have a background process that is running every couple of minutes to do a PullAsync on those widgets and also several other reference tables.

    The exception happened within that background process and may have occurred when the user was attempting to update a widget record they had just created.

    So if the background syncing is doing a PullAsync on the widget table, which first does a push and that item is in the process of being pushed and the user happens to try to update at the same time - is what when this exception would get thrown?  I would expect it would just update the item locally and get it next time around.  How would you suggest handling this possibility?  

    Tuesday, July 12, 2016 10:54 PM
  • This is happening a lot now.  I am wondering if we need to suspend the background sync when someone enters the edit page to avoid these issues.  The only thing I can think of is someone is trying to update an item that the sync service is currently trying to sync.

    Application Specific Information:
    *** Terminating app due to uncaught exception 'System.AggregateException', reason: 'System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.InvalidOperationException: The operation has been updated and cannot be updated again
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<TryUpdateOperation>d__38.MoveNext () <0x100d5c270 + 0x001a0> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<>c__DisplayClass37_0+<<UpdateOperationAsync>b__0>d.MoveNext () <0x100d5be10 + 0x00157> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<ExecuteOperationSafeAsync>d__44.MoveNext () <0x100d5e160 + 0x00733> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceTableOperationError+<UpdateOperationAsync>d__46.MoveNext () <0x100d536d0 + 0x0016b> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () <0x100267610 + 0x00017> in <filename unknown>:0 
      at FieldVisorMidstream.Services.SyncService+<TicketsResolveConflictsAsync>d__47.MoveNext () <0x100cbfc30 + 0x0054b> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () <0x100267610 + 0x00017> in <filename unknown>:0 
      at FieldVisorMidstream.Services.SyncService+<SyncTicketsAsync>d__46.MoveNext () <0x100cbefd0 + 0x00b5b> in <filename unknown>:0 
      --- End of inner exception stack trace ---
    ---> (Inner Exception #0) System.InvalidOperationException: The operation has been updated and cannot be updated again
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<TryUpdateOperation>d__38.MoveNext () <0x100d5c270 + 0x001a0> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<>c__DisplayClass37_0+<<UpdateOperationAsync>b__0>d.MoveNext () <0x100d5be10 + 0x00157> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext+<ExecuteOperationSafeAsync>d__44.MoveNext () <0x100d5e160 + 0x00733> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.GetResult () <0x100267070 + 0x00017> in <filename unknown>:0 
      at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceTableOperationError+<UpdateOperationAsync>d__46.MoveNext () <0x100d536d0 + 0x0016b> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () <0x100267610 + 0x00017> in <filename unknown>:0 
      at FieldVisorMidstream.Services.SyncService+<TicketsResolveConflictsAsync>d__47.MoveNext () <0x100cbfc30 + 0x0054b> in <filename unknown>:0 
    --- End of stack trace from previous location where exception was thrown ---
      at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <0x100267cb0 + 0x00028> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) <0x1002671b0 + 0x000d3> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) <0x100267100 + 0x0008b> in <filename unknown>:0 
      at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) <0x1002670a0 + 0x00047> in <filename unknown>:0 
      at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () <0x100267610 + 0x00017> in <filename unknown>:0 
      at FieldVisorMidstream.Services.SyncService+<SyncTicketsAsync>d__46.MoveNext () <0x100cbefd0 + 0x00b5b> in <filename unknown>:0 <---

    Wednesday, July 13, 2016 3:30 PM
  • Yes, you should definitely suspend the sync if the user is editing the item. Aside from the exception that you're seeing, you could end up with conflicting edits and the potential for losing server changes. For instance, if the user is updating record A and a sync is happening at the same time, and record A has been updated on the server, the user will not see the change. While it's possible to code around by attaching a listener to pull events, it's pretty complex and error prone.

    A more predictable user experience is to manually refresh before the user edits the record, and suspend automatic syncing. This will also prevent the exception you're seeing.

    Wednesday, July 13, 2016 9:18 PM
    Moderator
  • Thanks.  We have made some changes to try to account for this.  Do you see this being fixed in the future?  We are only working with and syncing up one entity now but in the future if we had many and various background processes syncing in the background it could get difficult to manage making sure it is impossible for these things to fire at the same time.
    Thursday, July 14, 2016 1:57 AM
  • You can file a bug report here (https://github.com/azure/azure-mobile-apps-net-client) but will probably be on the backlog for a while. This is partly due to the complexity of managing a secondary operation queue during the sync operation, but also because most apps would not behave correctly if they allowed edits while a sync is in progress. This is because the same record could be updated from the server while a user is editing it, or a previous edit can cause a conflict that needs to be resolved. This second case means that the programming model for conflict handling would also need to be revisited, since there can be more than one pending change.

    We'll definitely revisit if we get more customer requests, but so far the feedback we've heard is that a background sync causes these kinds of app bugs if it happens during an update or delete operation. The simplest solution is usually to pause syncing, rather than managing data changes and ensuring that the UI is consistent and does not discard user changes.

    Thursday, July 14, 2016 8:16 PM
    Moderator