Skip to content

Commit 93cdea5

Browse files
authored
fix(datastore): stop sync engine on non-retryable errors to allow restart (#1901)
* fix(datastore): stop sync engine on non-retryable errors to allow restart * add additional nil checks in sync engine
1 parent 706ea5f commit 93cdea5

File tree

6 files changed

+92
-12
lines changed

6 files changed

+92
-12
lines changed

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
202202
case .finished:
203203
break
204204
}
205+
stop { result in
206+
switch result {
207+
case .success:
208+
self.log.info("Stopping DataStore successful.")
209+
return
210+
case .failure(let error):
211+
self.log.error("Failed to stop StorageEngine with error: \(error)")
212+
}
213+
}
205214
}
206215

207216
@available(iOS 13.0, *)

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine+IncomingEventReconciliationQueueEvent.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@ extension RemoteSyncEngine {
3939
remoteSyncTopicPublisher.send(.subscriptionsInitialized)
4040
stateMachine.notify(action: .initializedSubscriptions)
4141
case .started:
42-
remoteSyncTopicPublisher.send(.subscriptionsActivated)
43-
if let api = self.api {
44-
stateMachine.notify(action: .activatedCloudSubscriptions(api,
45-
mutationEventPublisher,
46-
reconciliationQueue))
42+
guard let api = self.api else {
43+
let error = DataStoreError.internalOperation("api is unexpectedly `nil`", "", nil)
44+
stateMachine.notify(action: .errored(error))
45+
return
4746
}
47+
remoteSyncTopicPublisher.send(.subscriptionsActivated)
48+
stateMachine.notify(action: .activatedCloudSubscriptions(api,
49+
mutationEventPublisher,
50+
reconciliationQueue))
4851
case .paused:
4952
remoteSyncTopicPublisher.send(.subscriptionsPaused)
5053
case .mutationEventDropped, .mutationEventApplied:

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RemoteSyncEngine.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,13 @@ class RemoteSyncEngine: RemoteSyncEngineBehavior {
356356

357357
private func activateCloudSubscriptions() {
358358
log.debug(#function)
359-
reconciliationQueue?.start()
359+
guard let reconciliationQueue = reconciliationQueue else {
360+
let error = DataStoreError.internalOperation("reconciliationQueue is unexpectedly `nil`", "", nil)
361+
stateMachine.notify(action: .errored(error))
362+
return
363+
}
364+
365+
reconciliationQueue.start()
360366
}
361367

362368
private func startMutationQueue(api: APICategoryGraphQLBehavior,
Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import AmplifyTestCommon
1111
@testable import Amplify
1212
@testable import AWSDataStoreCategoryPlugin
1313

14-
class AWSAPICategoryPluginTests: XCTestCase {
14+
// swiftlint:disable type_body_length
15+
class AWSDataStorePluginTests: XCTestCase {
1516
func testStorageEngineDoesNotStartsOnConfigure() throws {
1617
let startExpectation = expectation(description: "Start Sync should not be called")
1718
startExpectation.isInverted = true
@@ -489,4 +490,64 @@ class AWSAPICategoryPluginTests: XCTestCase {
489490
}
490491
waitForExpectations(timeout: 1.0)
491492
}
493+
494+
func testStopStorageEngineOnTerminalEvent() {
495+
let storageEngine = MockStorageEngineBehavior()
496+
let stopExpectation = expectation(description: "stop should be called")
497+
var count = 0
498+
storageEngine.responders[.stopSync] = StopSyncResponder { _ in
499+
count = self.expect(stopExpectation, count, 1)
500+
}
501+
let storageEngineBehaviorFactory: StorageEngineBehaviorFactory = {_, _, _, _, _, _ throws in
502+
return storageEngine
503+
}
504+
let dataStorePublisher = DataStorePublisher()
505+
let plugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
506+
storageEngineBehaviorFactory: storageEngineBehaviorFactory,
507+
dataStorePublisher: dataStorePublisher,
508+
validAPIPluginKey: "MockAPICategoryPlugin",
509+
validAuthPluginKey: "MockAuthCategoryPlugin")
510+
511+
let semaphore = DispatchSemaphore(value: 0)
512+
plugin.start(completion: {_ in
513+
XCTAssertNotNil(plugin.storageEngine)
514+
XCTAssertNotNil(plugin.dataStorePublisher)
515+
semaphore.signal()
516+
})
517+
semaphore.wait()
518+
519+
storageEngine.mockPublisher.send(completion: .finished)
520+
521+
waitForExpectations(timeout: 1.0)
522+
}
523+
524+
func testStopStorageEngineOnTerminalFailureEvent() {
525+
let storageEngine = MockStorageEngineBehavior()
526+
let stopExpectation = expectation(description: "stop should be called")
527+
var count = 0
528+
storageEngine.responders[.stopSync] = StopSyncResponder { _ in
529+
count = self.expect(stopExpectation, count, 1)
530+
}
531+
let storageEngineBehaviorFactory: StorageEngineBehaviorFactory = {_, _, _, _, _, _ throws in
532+
return storageEngine
533+
}
534+
let dataStorePublisher = DataStorePublisher()
535+
let plugin = AWSDataStorePlugin(modelRegistration: TestModelRegistration(),
536+
storageEngineBehaviorFactory: storageEngineBehaviorFactory,
537+
dataStorePublisher: dataStorePublisher,
538+
validAPIPluginKey: "MockAPICategoryPlugin",
539+
validAuthPluginKey: "MockAuthCategoryPlugin")
540+
541+
let semaphore = DispatchSemaphore(value: 0)
542+
plugin.start(completion: {_ in
543+
XCTAssertNotNil(plugin.storageEngine)
544+
XCTAssertNotNil(plugin.dataStorePublisher)
545+
semaphore.signal()
546+
})
547+
semaphore.wait()
548+
549+
storageEngine.mockPublisher.send(completion: .failure(.internalOperation("", "", nil)))
550+
551+
waitForExpectations(timeout: 1.0)
552+
}
492553
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/SubscriptionSync/Support/MockSQLiteStorageEngineAdapter.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,9 @@ class MockStorageEngineBehavior: StorageEngineBehavior {
287287

288288
}
289289

290+
var mockPublisher = PassthroughSubject<StorageEngineEvent, DataStoreError>()
290291
var publisher: AnyPublisher<StorageEngineEvent, DataStoreError> {
291-
return PassthroughSubject<StorageEngineEvent, DataStoreError>().eraseToAnyPublisher()
292+
mockPublisher.eraseToAnyPublisher()
292293
}
293294

294295
func startSync(completion: @escaping DataStoreCallback<Void>) {

AmplifyPlugins/DataStore/DataStoreCategoryPlugin.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
6BC4FDAA23A899680027D20C /* MockRequestRetryablePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC4FDA923A899680027D20C /* MockRequestRetryablePolicy.swift */; };
144144
6BDC224023E21A4E007C8410 /* RemoteSyncEngineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BDC223F23E21A4E007C8410 /* RemoteSyncEngineTests.swift */; };
145145
6BDC224223E27324007C8410 /* MockAWSInitialSyncOrchestrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BDC224123E27324007C8410 /* MockAWSInitialSyncOrchestrator.swift */; };
146-
6BE7431C2575B8B000009FCB /* AWSAPICategoryPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE7431B2575B8B000009FCB /* AWSAPICategoryPluginTests.swift */; };
146+
6BE7431C2575B8B000009FCB /* AWSDataStorePluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE7431B2575B8B000009FCB /* AWSDataStorePluginTests.swift */; };
147147
6BE9D6F125A6643100AB5C9A /* StorageEngineTestsHasOne.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE9D6F025A6643100AB5C9A /* StorageEngineTestsHasOne.swift */; };
148148
6BE9D6F325A665EA00AB5C9A /* StorageEngineTestsBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE9D6F225A665EA00AB5C9A /* StorageEngineTestsBase.swift */; };
149149
6BE9D73E25A6800100AB5C9A /* StorageEngineTestsManyToMany.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE9D73D25A6800100AB5C9A /* StorageEngineTestsManyToMany.swift */; };
@@ -572,7 +572,7 @@
572572
6BC4FDA923A899680027D20C /* MockRequestRetryablePolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRequestRetryablePolicy.swift; sourceTree = "<group>"; };
573573
6BDC223F23E21A4E007C8410 /* RemoteSyncEngineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSyncEngineTests.swift; sourceTree = "<group>"; };
574574
6BDC224123E27324007C8410 /* MockAWSInitialSyncOrchestrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAWSInitialSyncOrchestrator.swift; sourceTree = "<group>"; };
575-
6BE7431B2575B8B000009FCB /* AWSAPICategoryPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSAPICategoryPluginTests.swift; sourceTree = "<group>"; };
575+
6BE7431B2575B8B000009FCB /* AWSDataStorePluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSDataStorePluginTests.swift; sourceTree = "<group>"; };
576576
6BE9D6F025A6643100AB5C9A /* StorageEngineTestsHasOne.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageEngineTestsHasOne.swift; sourceTree = "<group>"; };
577577
6BE9D6F225A665EA00AB5C9A /* StorageEngineTestsBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageEngineTestsBase.swift; sourceTree = "<group>"; };
578578
6BE9D73D25A6800100AB5C9A /* StorageEngineTestsManyToMany.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageEngineTestsManyToMany.swift; sourceTree = "<group>"; };
@@ -1585,7 +1585,7 @@
15851585
FAD2BDF423957F35006EB065 /* Core */ = {
15861586
isa = PBXGroup;
15871587
children = (
1588-
6BE7431B2575B8B000009FCB /* AWSAPICategoryPluginTests.swift */,
1588+
6BE7431B2575B8B000009FCB /* AWSDataStorePluginTests.swift */,
15891589
FA1C819E25868D17006160E9 /* AWSDataStorePluginAmplifyVersionableTests.swift */,
15901590
B40EF02724BF68C900F2264C /* ConfigurationTests.swift */,
15911591
21A4EE5B259D50C700E1047D /* DataStoreListDecoderTests.swift */,
@@ -2602,7 +2602,7 @@
26022602
FA4B8E942391C2CD009FC10F /* MutationIngesterConflictResolutionTests.swift in Sources */,
26032603
2104FE5028490638007CF949 /* StorageEngineTestsOptionalAssociation.swift in Sources */,
26042604
FA4A9557239ACAD7008E876E /* ModelReconciliationQueueBehaviorTests.swift in Sources */,
2605-
6BE7431C2575B8B000009FCB /* AWSAPICategoryPluginTests.swift in Sources */,
2605+
6BE7431C2575B8B000009FCB /* AWSDataStorePluginTests.swift in Sources */,
26062606
FA4A955D239AD810008E876E /* MockSQLiteStorageEngineAdapterResponders.swift in Sources */,
26072607
D80064F62499297800935DA3 /* MockFileManager.swift in Sources */,
26082608
21A4EE5C259D50C700E1047D /* DataStoreListDecoderTests.swift in Sources */,

0 commit comments

Comments
 (0)