amplify-swift icon indicating copy to clipboard operation
amplify-swift copied to clipboard

Error happened when I return back from offline mode and turn on the wifi, Also a crash happened if I restarted the data store again

Open medhatIbsais-Harri opened this issue 3 years ago • 7 comments

Describe the bug

When using DataStore, after configuring the Amplify and start syncing, try to turn off the wifi, then turn it on again, an error will be displayed in XCode logs, if you then forced syncing your DataStore by stopping the DataStore and started it again a crash will happen.

Steps To Reproduce

1. Open your app normally
2. wait until the DataStore and Amplify to be configured and synced
3. turn off the wifi
4. turn it on again
5. An error will be logged that there is an error caused by connection
6. force syncing the DataStore (stop DataStore, then start DataStore)
7. A crash will happen in Storage Engine

        Amplify.DataStore.stop { _ in
            Amplify.DataStore.start { _ in

            }
        }

Expected behavior

To sync data normally.

Amplify Framework Version

1.28.0

Amplify Categories

DataStore

Dependency manager

Cocoapods

Swift version

5.0

CLI version

Not Installed

Xcode version

13.3.1

Relevant log output

Error Log:

User receives a network connection status: true
************************************** HubPayload(eventName: "DataStore.networkStatus", context: nil, data: Optional(AmplifyPlugins.NetworkStatusEvent(active: true)))
2022-08-17 20:30:01.038161+0300 TeamHub[9288:290017] [RealtimeConnectionProvider] Realtime connection is stale, disconnecting.
2022-08-17 20:30:01.039196+0300 TeamHub[9288:290017] ConnectionProviderError.connection
2022-08-17 20:30:01.039787+0300 TeamHub[9288:290017] ConnectionProviderError.connection
2022-08-17 20:30:01.042814+0300 TeamHub[9288:290017] ConnectionProviderError.connection
2022-08-17 20:30:01.055788+0300 TeamHub[9288:290070] [AWSModelReconciliationQueue] receiveCompletion: error: DataStoreError: Subscription item event failed with error
Caused by:
APIError: Subscription item event failed with error
Caused by:
connection
2022-08-17 20:30:01.060776+0300 TeamHub[9288:290017] [AWSDataStorePlugin] StorageEngine completed with error: DataStoreError: Subscription item event failed with error
Caused by:
DataStoreError: Subscription item event failed with error
Caused by:
APIError: Subscription item event failed with error
Caused by:
connection

------------------------------------------------------------------------------------------------

Crash stack trace:

* thread #1, queue = 'AWSDataStorePlugin.storageEngineInitQueue', stop reason = EXC_BREAKPOINT (code=1, subcode=0x102bc5b50)
    frame #0: 0x0000000102bc5b50 libdispatch.dylib`__DISPATCH_WAIT_FOR_QUEUE__ + 456
    frame #1: 0x0000000102bc551c libdispatch.dylib`_dispatch_sync_f_slow + 172
    frame #2: 0x0000000199cede18 libswiftDispatch.dylib`merged implicit closure #2 (() -> ()) -> () in implicit closure #1 (__C.OS_dispatch_queue) -> (() -> ()) -> () in __C.OS_dispatch_queue.sync<τ_0_0>(execute: () throws -> τ_0_0) throws -> τ_0_0 + 152
    frame #3: 0x0000000199ced0ac libswiftDispatch.dylib`partial apply forwarder for implicit closure #2 (() -> ()) -> () in implicit closure #1 (__C.OS_dispatch_queue) -> (() -> ()) -> () in __C.OS_dispatch_queue.sync<τ_0_0>(execute: () throws -> τ_0_0) throws -> τ_0_0 + 40
    frame #4: 0x0000000199cedbb0 libswiftDispatch.dylib`__C.OS_dispatch_queue._syncHelper<τ_0_0>(fn: (() -> ()) -> (), execute: () throws -> τ_0_0, rescue: (Swift.Error) throws -> τ_0_0) throws -> τ_0_0 + 256
    frame #5: 0x0000000199ced140 libswiftDispatch.dylib`__C.OS_dispatch_queue.sync<τ_0_0>(execute: () throws -> τ_0_0) throws -> τ_0_0 + 140
  * frame #6: 0x00000001039dd5cc AmplifyPlugins`AWSDataStorePlugin.initStorageEngine(self=0x00000001040519f0) at AWSDataStorePlugin.swift:114:32
    frame #7: 0x00000001039de4c0 AmplifyPlugins`AWSDataStorePlugin.initStorageEngineAndStartSync(completion=0x00000001039e8b40 AmplifyPlugins`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in AmplifyPlugins.AWSDataStorePlugin.start(completion: (Swift.Result<(), Amplify.DataStoreError>) -> ()) -> () at <compiler-generated>, self=0x00000001040519f0) at AWSDataStorePlugin.swift:146:16
    frame #8: 0x00000001039e8a88 AmplifyPlugins`AWSDataStorePlugin.start(completion=0x00000001004d8a78 TeamHub`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in TeamHub.AmplifyManager.syncDataStore(completion: () -> ()) -> () at <compiler-generated>, self=0x00000001040519f0) at AWSDataStorePlugin+DataStoreBaseBehavior.swift:268:9
    frame #9: 0x00000001039eab84 AmplifyPlugins`protocol witness for DataStoreBaseBehavior.start(completion:) in conformance AWSDataStorePlugin at <compiler-generated>:0
    frame #10: 0x0000000102e4ea20 Amplify`DataStoreCategory.start(completion=0x00000001004d8a78 TeamHub`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in TeamHub.AmplifyManager.syncDataStore(completion: () -> ()) -> () at <compiler-generated>, self=0x000000028343b270) at DataStoreCategory+Behavior.swift:78:16
    frame #11: 0x00000001004d61ec TeamHub`closure #1 in AmplifyManager.syncDataStore(_0=(success = () @ 0x000000016fa38930), completion=0x000000010044a7f0 TeamHub`closure #1 () -> () in TeamHub.EmployeeLoginViewController.didClickLoginButton() -> () at EmployeeLoginViewController.swift:278:9) at AmplifyManager.swift:155:31
    frame #12: 0x00000001039e91f0 AmplifyPlugins`closure #1 in AWSDataStorePlugin.stop(self=0x00000001040519f0, completion=0x00000001004d6248 TeamHub`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in TeamHub.AmplifyManager.syncDataStore(completion: () -> ()) -> () at <compiler-generated>) at AWSDataStorePlugin+DataStoreBaseBehavior.swift:285:17
    frame #13: 0x00000001039e96b8 AmplifyPlugins`thunk for @callee_guaranteed () -> () at <compiler-generated>:0
    frame #14: 0x00000001039e9718 AmplifyPlugins`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0
    frame #15: 0x0000000102bb5fc8 libdispatch.dylib`_dispatch_client_callout + 16
    frame #16: 0x0000000102bc5790 libdispatch.dylib`_dispatch_lane_barrier_sync_invoke_and_complete + 116
    frame #17: 0x00000001039e8cd0 AmplifyPlugins`AWSDataStorePlugin.stop(completion=0x00000001004d6248 TeamHub`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in TeamHub.AmplifyManager.syncDataStore(completion: () -> ()) -> () at <compiler-generated>, self=0x00000001040519f0) at AWSDataStorePlugin+DataStoreBaseBehavior.swift:274:32
    frame #18: 0x00000001039eaba4 AmplifyPlugins`protocol witness for DataStoreBaseBehavior.stop(completion:) in conformance AWSDataStorePlugin at <compiler-generated>:0
    frame #19: 0x0000000102e4eab0 Amplify`DataStoreCategory.stop(completion=0x00000001004d6248 TeamHub`partial apply forwarder for closure #1 (Swift.Result<(), Amplify.DataStoreError>) -> () in TeamHub.AmplifyManager.syncDataStore(completion: () -> ()) -> () at <compiler-generated>, self=0x000000028343b270) at DataStoreCategory+Behavior.swift:82:16
    frame #20: 0x00000001004d6100 TeamHub`AmplifyManager.syncDataStore(completion=0x000000010044a7f0 TeamHub`closure #1 () -> () in TeamHub.EmployeeLoginViewController.didClickLoginButton() -> () at EmployeeLoginViewController.swift:278:9, self=0x0000000282f2b740) at AmplifyManager.swift:154:27
    frame #21: 0x000000010044a7d8 TeamHub`EmployeeLoginViewController.didClickLoginButton(self=0x0000000103811650) at EmployeeLoginViewController.swift:276:31
    frame #22: 0x000000010044a818 TeamHub`@objc EmployeeLoginViewController.didClickLoginButton() at <compiler-generated>:0
    frame #23: 0x0000000183e9c0b4 UIKitCore`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #24: 0x0000000183fbb20c UIKitCore`-[UIControl sendAction:to:forEvent:] + 124
    frame #25: 0x0000000183d5143c UIKitCore`-[UIControl _sendActionsForEvents:withEvent:] + 352
    frame #26: 0x0000000183de8318 UIKitCore`-[UIButton _sendActionsForEvents:withEvent:] + 156
    frame #27: 0x000000018405feb0 UIKitCore`-[UIControl touchesEnded:withEvent:] + 516
    frame #28: 0x0000000183b65e74 UIKitCore`-[UIWindow _sendTouchesForEvent:] + 1228
    frame #29: 0x0000000183b95994 UIKitCore`-[UIWindow sendEvent:] + 4372
    frame #30: 0x0000000183d36504 UIKitCore`-[UIApplication sendEvent:] + 892
    frame #31: 0x0000000183b6a974 UIKitCore`__dispatchPreprocessedEventFromEventQueue + 8148
    frame #32: 0x0000000183b5f838 UIKitCore`__processEventQueue + 6544
    frame #33: 0x0000000183b64c54 UIKitCore`__eventFetcherSourceCallback + 168
    frame #34: 0x000000018177e4ec CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    frame #35: 0x000000018178e61c CoreFoundation`__CFRunLoopDoSource0 + 204
    frame #36: 0x00000001816d0824 CoreFoundation`__CFRunLoopDoSources0 + 256
    frame #37: 0x00000001816d5ef8 CoreFoundation`__CFRunLoopRun + 768
    frame #38: 0x00000001816e9240 CoreFoundation`CFRunLoopRunSpecific + 572
    frame #39: 0x00000001a1ff3988 GraphicsServices`GSEventRunModal + 160
    frame #40: 0x0000000183ee941c UIKitCore`-[UIApplication _run] + 1080
    frame #41: 0x0000000183c82b88 UIKitCore`UIApplicationMain + 336
    frame #42: 0x00000001004b545c TeamHub`main at AppDelegate.swift:15:7
    frame #43: 0x000000010170c3d0 dyld`start + 444

Is this a regression?

Yes

Regression additional context

No response

Device

iPad 5th generation

iOS Version

15.5

Specific to simulators

No response

Additional context

No response

medhatIbsais-Harri avatar Aug 17 '22 18:08 medhatIbsais-Harri

Thanks for reporting this. We're tracking a related issue here.

ameter avatar Aug 17 '22 19:08 ameter

Thanks for reporting this. We're tracking a related issue here.

Ok thank you, but also there is another part for this issue that it causing a crash if you stopped and started the DataStore again.

when this error appeared "DataStoreError: Subscription item event failed with error Caused by: APIError: Subscription item event failed with error Caused by: connection"

try to execute this code below, the app will crash

    Amplify.DataStore.stop { _ in
        Amplify.DataStore.start { _ in

        }
    }

medhatIbsais-Harri avatar Aug 17 '22 19:08 medhatIbsais-Harri

Hello @ameter, I need to ask a question, are there any way to know that the DataStore is stopped? like a boolean flag or something?

or a way to know that the above failure happened?

medhatIbsais-Harri avatar Aug 17 '22 20:08 medhatIbsais-Harri

Unfortunately there is not a good event to know that DataStore has stopped in this case. However, calling DataStore stop before start here is unnecessary. Calling start alone should recover from this situation. In addition, any DataStore operation (save, query, delete, etc.) will also start DataStore if it is not already started. The crash is still unexpected behavior so thank you for reporting that.

I see based on the logs that you provided that you are attempting to use the networkStatus hub event as a work around. Unfortunately this will not work because this event is dispatched before DataStore is stopped due to the logic in https://github.com/aws-amplify/amplify-ios/pull/1901. This behavior is intentional to fix a separate issue, however it has unintended side effects here.

All this to say is that this issue will break real time subscriptions, but the remainder of DataStore should function as expected.

We don't have an ETA on the fix at this time.

dpilch avatar Aug 17 '22 20:08 dpilch

@dpilch Thank you for your answer, Yes I know that starting the DataStore will avoid the crash, but we have a use case that we are providing the user a force sync button, he can click on it to force sync everything from AppSync, so if the user turn on the wifi and clicked this button the app will crash, because this button implementation is to stop the DataStore and start it again.

force sync button implementation:

    Amplify.DataStore.stop { _ in
        Amplify.DataStore.start { _ in

        }
    }

medhatIbsais-Harri avatar Aug 17 '22 21:08 medhatIbsais-Harri

Ah, I understand. I would say for the time being the solution would be to wrap the stop with another start. This isn't the prettiest solution, but will be fine because DataStore start is a no-op when already started.

Amplify.DataStore.start { _ in
    Amplify.DataStore.stop { _ in
        Amplify.DataStore.start { _ in

        }
    }
}

We will continue to look into the fix for crash as well as the incorrect stopping outlined in https://github.com/aws-amplify/amplify-ios/issues/2152

dpilch avatar Aug 18 '22 15:08 dpilch

@dpilch Yes I did that recently to avoid the crash and to maintain the app to work normally for now. Thank you for your collaboration 🙏🏻

medhatIbsais-Harri avatar Aug 18 '22 15:08 medhatIbsais-Harri

Hi @medhatIbsais-Harri, thanks for reporting this issue. the following code snippet should not crash the app

Amplify.DataStore.stop { _ in
            Amplify.DataStore.start { _ in

            }
        }

Glad @dpilch's workaround is working for you. we'll keep this issue open until we have a fix for the above code snippet does not crash an app

lawmicha avatar Oct 24 '22 20:10 lawmicha

Hi @lawmicha, thank you for your collaboration, but the code snippet below will crash the app, the idea if you request Amplify.DataStore.stop while it’s already stopped, this will crash the app, so that I used the workaround which is to request DataStore.start, then DataStore.Stop, then DataStore.start again, so that I avoid the crash.

  Amplify.DataStore.stop { _ in
              Amplify.DataStore.start { _ in
  
              }
          }

medhatIbsais-Harri avatar Oct 24 '22 20:10 medhatIbsais-Harri

We were able to reproduce the crash and the issue is that start is trying to perform the work synchronously on the same DispatchQueue that stop is currently using. This causes a deadlock because start waits for the queue but is never able to acquire it, since start is called in the completion closure of stop. To get around this, you can dispatch the call to start on a separate thread, for example

Amplify.DataStore.stop { _ in 
    DispatchQueue.global(qos: .background).async {
        Amplify.DataStore.start { _ in
            
        }
    }
}

We have the PR in progress to fix so that you do not have to do the workaround above: https://github.com/aws-amplify/amplify-swift/pull/2517

lawmicha avatar Oct 28 '22 21:10 lawmicha

@lawmicha thank you, we did another workaround and its working for now, we will wait for your fix

medhatIbsais-Harri avatar Oct 30 '22 07:10 medhatIbsais-Harri

Hi @medhatIbsais-Harri you should be able to upgrade to version 1.28.3, we've released the fix for this issue. Please let us know if you continue to experience any issues. 🙏

chrisbonifacio avatar Nov 11 '22 19:11 chrisbonifacio

Thank you @chrisbonifacio

medhatIbsais-Harri avatar Nov 13 '22 11:11 medhatIbsais-Harri

Hello @chrisbonifacio, I'm still experiencing this issue on Amplify (1.28.3) the crash problem is resolved but still receiving this error logs when I return back from offline mode to online mode

2022-11-30 16:16:19.507663+0200 TeamHub Pro[2793:73400] [RealtimeConnectionProvider] Realtime connection is stale, disconnecting.
2022-11-30 16:16:19.508623+0200 TeamHub Pro[2793:73400] ConnectionProviderError.connection
2022-11-30 16:16:19.509441+0200 TeamHub Pro[2793:73400] ConnectionProviderError.connection
2022-11-30 16:16:19.510948+0200 TeamHub Pro[2793:73400] ConnectionProviderError.connection
2022-11-30 16:16:19.519136+0200 TeamHub Pro[2793:73451] [AWSModelReconciliationQueue] [InitializeSubscription.3] AWSModelReconciliationQueue receiveCompletion: error: DataStoreError: Subscription item event failed with error
Caused by:
APIError: Subscription item event failed with error
Caused by:
connection
2022-11-30 16:16:19.522977+0200 TeamHub Pro[2793:73400] [AWSDataStorePlugin] StorageEngine completed with error: DataStoreError: Subscription item event failed with error
Caused by:
DataStoreError: Subscription item event failed with error
Caused by:
APIError: Subscription item event failed with error
Caused by:
connection

medhatIbsais-Harri avatar Nov 30 '22 14:11 medhatIbsais-Harri

Hello @chrisbonifacio, any updates here?

medhatIbsais-Harri avatar Dec 11 '22 06:12 medhatIbsais-Harri

Hello @chrisbonifacio @lawmicha, any updates here?

medhatIbsais-Harri avatar Dec 20 '22 08:12 medhatIbsais-Harri