-
Notifications
You must be signed in to change notification settings - Fork 200
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
Subscriptions, State machine for ReconcileAndLocalSaveOperation #149
Conversation
- Remove AWSDataStoreCategoryPlugin references that got reinstated after merge
e4ec5b0
to
7618217
Compare
- Initial subscriptions are now performed at startup
…t resolution handling
- Mutation queue is now an OperationQueue instead of a Combine stream - Add 'unknown' case to DataStoreError - Fix SQLite tests and disable init logging for SQLiteStorageEngineAdapter
* master: API Predicate to GraphQL filter variables (#150) model associations: refactor + missing use cases (#153) Basic unit tests for comprehend and translate (#160) CoreML logic to Detect faces (#155) API Category - Updates to APIError and GraphQLResponse (#133) Initial commit for unit test for translate service behavior (#158) bug fix change (#152)
* master: fix API model association (#163)
There was a problem hiding this 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 file comparison checkpoint
Note to reviewers: I will move |
…agated to our subscriptions
if models.count > 1 { | ||
completion(.failure(.nonUniqueResult(model: modelType.modelName, count: count))) | ||
} else { | ||
completion(.success(models.first)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like we should reverse this in the event that models is empty.
if models.count == 1 {
completion(.success(...
} else {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon reflection I think I'll change it to a guard
to really capture the intent that this is an error case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon even more reflection, I now remember why I did it this way: a 0-count model array is also valid!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch
to the rescue:
switch models.count {
case 0, 1:
completion(.success(models.first))
default:
completion(.failure(.nonUniqueResult(model: modelType.modelName, count: models.count)))
}
/// mutated data from the service. | ||
static let subscriptionReceived = "DataStore.subscriptionReceived" | ||
/// Dispatched when DataStore receives a sync response from the cloud via the API category. This event does not | ||
/// define the source of the event--it could be in response to either a subscription or a locally-sourced mutation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently this we seem to only be using the variable in the subscription flow (ReconcileAndLocalSaveOperation.swift) -- maybe it would be better to have two separate variables -- one so that customers can listen to subscription events, and one for when location mutations are made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that, but the comment explains why I don't think it's a meaningful distinction: any incoming event could potentially overwrite the data in the local store, regardless of source. What would the customer use case be for ignoring one type over the other, given that either could result in a change?
.../DataStore/AWSDataStoreCategoryPlugin/AWSDataStoreCategoryPlugin+DataStoreBaseBehavior.swift
Outdated
Show resolved
Hide resolved
...ifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/IncomingEventReconciliationQueues.swift
Outdated
Show resolved
Hide resolved
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, we have
OutgoingMutationQueue.swift
and
SyncMutationToCloudOperation.swift
Maybe it would be clearer to rename these to:
OutgoingMutationOperationQueue.swift
and
OutgoingMutationOperation.swift
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the "outgoing mutation" includes saving the local mutation event as well as creating & enqueing the cloud sync operations. The SyncMutationToCloudOperation
only does that one thing.
Part of the problem is that the OutgoingMutationQueue is doing too much, at too many different levels:
- loading initial mutations from disk (infrastructure @ global scope)
- Creating a sync operation from a loaded mutation event (infrastructure at local scope)
- accepting incoming mutation submissions, creating a sync operation from it (transactional at system scope)
The SyncMutationToCloudOperation on the other hand is a little bit more targeted:
- send to cloud (
- validate response
- notify
Rather than just rename the operation, I'd rather refactor the queue to do less itself & delegate more, and enforce a better separation of levels of responsibility. Thoughts?
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/ReconcileAndLocalSaveOperation.swift
Outdated
Show resolved
Hide resolved
...re/AWSDataStoreCategoryPlugin/Sync/SubscriptionSync/IncomingSubscriptionEventPublisher.swift
Outdated
Show resolved
Hide resolved
...WSDataStoreCategoryPlugin/Sync/SubscriptionSync/AsyncSubscriptionEventToAnyModelMapper.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments are minor.. I'm largely good with broad framework for both outgoing/ingoing mutations as well as subscriptions. We can iterate from here! thanks!!
AmplifyPlugins/API/AWSAPICategoryPluginFunctionalTests/APICategoryPluginConcurrencyTests.swift
Outdated
Show resolved
Hide resolved
...gins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/SubscriptionIntegrationTests.swift
Outdated
Show resolved
Hide resolved
Addressed PR feedback (less a few open questions for further discussion). Merging now to serve as a base for upcoming changes--notably #161 to stop integration tests from crashing :( |
Notes V2
Notes V1
ReconcileAndLocalSaveOperation
that will handle any incoming cloud sync events, whether from mutations or subscriptions.StateMachine
class that we can promote to an AWSPluginsCore support type if it looks useful in other contextsDefaultLogger
support protocol to provide a defaultlog
property.Amplify.reset
. Tracked in Make Logging and Hub categories available at initialization #161_deleted
conflict resolution field alongside the previously-existing_version
field. We'll remove those once @drochetti finishes conflict resolutionNote to reviewers
Many of the integration tests added in this PR are broken due to errors in connections handling. Once codegen/CLI changes are pushed, and #164 is merged, I'll dive deeper and get those fixed.
@drochetti Could you please pay special attention to the changes I made to model & schema, especially the optional field handling in
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Storage/SQLite/Model+SQLite.swift
sqlValues(for fields:)
? Unit tests are passing, but I haven't added additional tests to cover this case and I want to get another set of eyes on this to validate my thinking.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.