Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial sync startup/3-way merge #238

Merged
merged 3 commits into from
Dec 9, 2019
Merged

Initial sync startup/3-way merge #238

merged 3 commits into from
Dec 9, 2019

Conversation

palpatim
Copy link
Member

@palpatim palpatim commented Dec 6, 2019

  • Initial implementation of InitialSyncOrchestrator, integrated with
    ReconciliationQueue to apply incoming sync query results
  • Added a buffer queue for incoming remote events to ReconciliationQueue, so
    remote API sync can be turned off independently of applying mutations from
    sync queries
  • Made CancelAwareBlockOperation a standalone class
  • Model extensions
    • Change ModelSchema+Syncable to ModelSchema+Attributes
    • Added 'ModelSchema.isSystem' convenience getter
    • Change 'hasSyncableModels' to look for the existence of any non-system
      models; all models are considered syncable by default (no local model support
      at launch)
    • Added ModelGraphs to track Model connection dependencies for initial sync
  • Made AtomicValue public so it can be used in plugins; added convenience
    methods for RangeReplaceableCollection
  • Removed isSyncable schema attribute in favor of designating all non-system
    models as syncable
  • Added buffer queue for incoming subscription event
    submission to reconciliation queue
  • Added 'DataStoreError.internalOperation' to contain errors about nil weak
    references being unavailable
  • Added convenience DataStoreError constructor for missing reconciliation queue
  • Fix some linting warnings
  • Test cleanup throughout
  • Added responders to MockAPICategoryPlugin to let us invoke callback of methods
  • Convert ModelRegistry.register to take protocol argument rather than concrete type

Description of changes:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

- Initial implementation of InitialSyncOrchestrator, integrated with
  ReconciliationQueue to apply incoming sync query results
- Added a buffer queue for incoming remote events to ReconciliationQueue, so
  remote API sync can be turned off indpendently of applying mutations from
  sync queries
- Made CancelAwareBlockOperation a standalone class
- Model extensions
  - Change ModelSchema+Syncable to ModelSchema+Attributes
  - Added 'ModelSchema.isSystem' convenience getter
  - Change 'hasSyncableModels' to look for the existence of any non-system
    models; all models are considered syncable by default (no local model support
    at launch)
  - Added ModelGraphs to track Model connection dependencies for initial sync
- Made AtomicValue public so it can be used in plugins; added convenience
  methods for RangeReplaceableCollection
- Removed isSyncable schema attribute in favor of designating all non-system
  models as syncable; added buffer queue for incoming subscription event
  submission to reconciliation queue; refactoring & renaming
- Added 'DataStore.internalOperation' to contain errors about nil weak
  references being unavailable
- Added convenience DataStoreError constructor for missing reconciliation queue
- Fix some linting warnings
- Minor test cleanup
- Added responders to MockAPICategoryPlugin to let us invoke callback of methods
- Added unit tests for InitialSyncOperation happy path
…concrete type

- InitialSyncOrchestrator unit tests
@palpatim palpatim added the datastore Issues related to the DataStore category label Dec 6, 2019
Copy link
Member Author

@palpatim palpatim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self review to set checkpoint

Copy link
Contributor

@lawmicha lawmicha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving some initial comments and opening issue for API category's Model based GraphQL APIs dependency on ModelRegistry's isSyncable method #239

Comment on lines 44 to 49
if #available(iOS 13, *) {
let syncEngine = isSyncEnabled ? try? RemoteSyncEngine(storageAdapter: storageAdapter) : nil
self.init(storageAdapter: storageAdapter, syncEngine: syncEngine, isSyncEnabled: isSyncEnabled)
self.init(storageAdapter: storageAdapter, syncEngine: syncEngine)
} else {
self.init(storageAdapter: storageAdapter, syncEngine: nil, isSyncEnabled: isSyncEnabled)
self.init(storageAdapter: storageAdapter, syncEngine: nil)
}
Copy link
Contributor

@lawmicha lawmicha Dec 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to check if Amplify.API is configured here? if it's iOS13 && Amplify.API.isConfigured then create a RemoveSyncEngine with storageAdapter and Amplify.API. I would have imagined RemoteSyncEngine to always need an API when being constructed.

I don't have a real good use case to expose isConfigured at the Category level except that whenever pluginKey's do not match the plugin's key, then the plugin that was added to Amplify doesn't get called on the plugin's configure() method, which developer will then find out it is not configured at plugin's API calls. And also in this case where plugins are seeing if another plugin is configured. DataStore checking if API for sync, API checking for DataStore for Model based GraphQL calls,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to check if Amplify.API is configured here?

Not yet, but it's something we need to figure out. Currently I'm of two minds:

  1. Expose an explicit isConfigured check on the category, as you discuss, and note it as internal in the docs. I also can't think of a good customer-facing use case, but I don't know of a way to expose an internal property across modules without resorting to Objective-C.
  2. Do away with isConfigured checks altogether except if the customer adds a plugin. Other categories would be fulfilled by no-op operations that invoke errors on their callbacks as soon as they're created. That adds more runtime complexity to the Amplify core, though.

We're going to have to answer this question once and for all, and soon, since our cross-category use cases are going to grow: Predictions->Storage (upload an image to Storage so Predictions can identify entities in it); or DataStore->Storage (complex object support); or Analytics as a "middleware" plugin that intercepts Hub events and auto-logs messages.

Amplify.xcodeproj/project.pbxproj Show resolved Hide resolved
@@ -28,290 +28,296 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
004DE85F3AE8FFE0816925652FFFBB75 /* AWSCognitoCredentialsProvider+Extension.h in Headers */ = {isa = PBXBuildFile; fileRef = 953E533AB3626686BC0DCFEE4DCDBCC9 /* AWSCognitoCredentialsProvider+Extension.h */; settings = {ATTRIBUTES = (Public, ); }; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've typically avoided commiting this file, as well as the .lock files... do we need to commit these files?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a team discussion about this. Guidance from CocoaPods (and my personal preference) is that we should commit Pods, manifest & lock to the repo, as they are necessary for non-CocoaPods systems (e.g., Carthage) to build. However, we haven't propagated that pattern into the plugin folders, and I'd like to understand other points of view.

Copy link
Member Author

@palpatim palpatim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responding to PR comments

Comment on lines 44 to 49
if #available(iOS 13, *) {
let syncEngine = isSyncEnabled ? try? RemoteSyncEngine(storageAdapter: storageAdapter) : nil
self.init(storageAdapter: storageAdapter, syncEngine: syncEngine, isSyncEnabled: isSyncEnabled)
self.init(storageAdapter: storageAdapter, syncEngine: syncEngine)
} else {
self.init(storageAdapter: storageAdapter, syncEngine: nil, isSyncEnabled: isSyncEnabled)
self.init(storageAdapter: storageAdapter, syncEngine: nil)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to check if Amplify.API is configured here?

Not yet, but it's something we need to figure out. Currently I'm of two minds:

  1. Expose an explicit isConfigured check on the category, as you discuss, and note it as internal in the docs. I also can't think of a good customer-facing use case, but I don't know of a way to expose an internal property across modules without resorting to Objective-C.
  2. Do away with isConfigured checks altogether except if the customer adds a plugin. Other categories would be fulfilled by no-op operations that invoke errors on their callbacks as soon as they're created. That adds more runtime complexity to the Amplify core, though.

We're going to have to answer this question once and for all, and soon, since our cross-category use cases are going to grow: Predictions->Storage (upload an image to Storage so Predictions can identify entities in it); or DataStore->Storage (complex object support); or Analytics as a "middleware" plugin that intercepts Hub events and auto-logs messages.

@palpatim palpatim merged commit f4b0423 into master Dec 9, 2019
@palpatim palpatim deleted the palpatim/3-way-merge branch December 9, 2019 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
datastore Issues related to the DataStore category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants