Skip to content

Commit 67a1c61

Browse files
authored
fix: Fix data store mutation when restoring network (#1345)
Fixes an issue in DataStore where it dropped consecutive updates to a model if received while the network was not connected. As part of this fix, we simplified the OutgoingMutationQueue state machine and cleaned up potential race conditions in state synchronization between RemoteSyncEngine and OutgoingMutationQueue. - fix: Fix data races in MutationRetryNotifier encountered in some test situations. It's unclear whether this would be encountered in production since the production model includes additional queue protections. - fix: Fix retain cycles in RemoteSyncEngine - fix: RemoteSyncEngine now correctly sets up publisher notifications for custom reachability publishers - test: Change SyncEngineTestBase reachabilityPublisher to be CurrentValueSubject - test: DataStore sync tests can now specify an on-disk SQLite file rather than only an in-memory SQLite database to back the DataStore. - test: API category can now specify a custom reachability publisher - test: fix Amplify.reset(). This includes explicitly declaring Resettable conformance for a few types that were missing it, protecting `Logger` with an AtomicValue since it is used during the actual reset() flow, and adding verbose logging to reset flows to help identify race conditions or deadlocks in future. Amplify.reset() is also now synchronous, although Resettable.reset() still accepts a callback. - test: Overall DataStore test stability fixes
1 parent 6696bac commit 67a1c61

File tree

48 files changed

+1058
-364
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1058
-364
lines changed

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,24 @@ amplifyconfiguration.json
5050
credentials-mc.json
5151

5252
fastlane/report.xml
53+
54+
# Amplify artifacts, such as used for integ tests
55+
amplify
56+
amplify/\#current-cloud-backend
57+
amplify/.config/local-*
58+
amplify/logs
59+
amplify/mock-data
60+
amplify/backend/amplify-meta.json
61+
amplify/backend/awscloudformation
62+
amplify/backend/.temp
63+
build/
64+
dist/
65+
node_modules/
66+
aws-exports.js
67+
awsconfiguration.json
68+
amplifyconfiguration.json
69+
amplifyconfiguration.dart
70+
amplify-build-config.json
71+
amplify-gradle-config.json
72+
amplifytools.xcconfig
73+
.secret-*

Amplify/Amplify.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,21 @@ public class Amplify {
3030
public static internal(set) var Auth = AuthCategory()
3131
public static internal(set) var DataStore = DataStoreCategory()
3232
public static internal(set) var Hub = HubCategory()
33-
public static internal(set) var Logging = LoggingCategory()
3433
public static internal(set) var Predictions = PredictionsCategory()
3534
public static internal(set) var Storage = StorageCategory()
3635

36+
// Special case category. We protect this with an AtomicValue because it is used by reset()
37+
// methods during setup & teardown of tests
38+
public static internal(set) var Logging: LoggingCategory {
39+
get {
40+
loggingAtomic.get()
41+
}
42+
set {
43+
loggingAtomic.set(newValue)
44+
}
45+
}
46+
private static let loggingAtomic = AtomicValue<LoggingCategory>(initialValue: LoggingCategory())
47+
3748
/// Adds `plugin` to the Analytics category
3849
///
3950
/// - Parameter plugin: The AnalyticsCategoryPlugin to add

Amplify/Categories/API/Internal/APICategory+Resettable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ extension AmplifyAPICategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

24+
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry")
2025
ModelRegistry.reset()
2126
ModelListDecoderRegistry.reset()
27+
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry: finished")
2228

2329
group.wait()
2430

Amplify/Categories/Analytics/Internal/AnalyticsCategory+Resettable.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ extension AnalyticsCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

2024
group.wait()

Amplify/Categories/Auth/Internal/AuthCategory+Resettable.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ extension AuthCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

2024
group.wait()

Amplify/Categories/DataStore/Internal/DataStoreCategory+Resettable.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ extension DataStoreCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

24+
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry")
2025
ModelRegistry.reset()
2126
ModelListDecoderRegistry.reset()
27+
log.verbose("Resetting ModelRegistry and ModelListDecoderRegistry: finished")
2228

2329
group.wait()
2430

Amplify/Categories/Hub/Internal/HubCategory+Resettable.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ extension HubCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

2024
group.wait()

Amplify/Categories/Logging/Internal/LoggingCategory+Resettable.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import Foundation
1010
extension LoggingCategory: Resettable {
1111

1212
public func reset(onComplete: @escaping BasicClosure) {
13+
log.verbose("Resetting \(categoryType) plugin: no 'finish' message will be logged")
1314
concurrencyQueue.sync {
1415
let group = DispatchGroup()
1516

1617
group.enter()
17-
18-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
group.leave()
20+
}
1921

2022
group.wait()
2123

Amplify/Categories/Predictions/Internal/PredictionsCategory+Resettable.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ extension PredictionsCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

2024
group.wait()

Amplify/Categories/Storage/Internal/StorageCategory+Resettable.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ extension StorageCategory: Resettable {
1313
let group = DispatchGroup()
1414

1515
for plugin in plugins.values {
16+
log.verbose("Resetting \(categoryType) plugin")
1617
group.enter()
17-
plugin.reset { group.leave() }
18+
plugin.reset {
19+
self.log.verbose("Resetting \(self.categoryType) plugin: finished")
20+
group.leave()
21+
}
1822
}
1923

2024
group.wait()

0 commit comments

Comments
 (0)