-
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
feat(datastore): Dispatch outboxStatus, subscriptionsEstablished, syncQueriesStarted events #721
Conversation
7db15ce
to
5c578a9
Compare
Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOperation.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOperation.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOperation.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Support/ModelSyncedPayload.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Support/ModelSyncedPayload.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Support/ModelSyncedPayload.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Support/ModelSyncedPayload.swift
Outdated
Show resolved
Hide resolved
...Store/AWSDataStoreCategoryPluginTests/TestSupport/Mocks/MockAWSInitialSyncOrchestrator.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOperation.swift
Outdated
Show resolved
Hide resolved
...ifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreEndToEndTests.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.
review for syncQueriesReady
...yPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOrchestrator.swift
Outdated
Show resolved
Hide resolved
...yPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOrchestrator.swift
Outdated
Show resolved
Hide resolved
...yPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOrchestrator.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.
review subscriptionsEstablished
Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.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.
partial review for outboxStatus
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.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.
continued review for outboxStatus
Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
...yPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOrchestrator.swift
Outdated
Show resolved
Hide resolved
...yPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/InitialSync/InitialSyncOrchestrator.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/OutboxStatusEvent.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/SyncQueriesStartedEvent.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
can update title to be more explicit on the hub events being added? |
One approach i'm thinking is in OutgoingMutationQueue, there is a state that is when in
Then
This approach goes straight to introducing a new state and responder method, however you can try it out by putting |
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/OutboxStatusEvent.swift
Outdated
Show resolved
Hide resolved
can you add integration test that covers recieving the new events you are emitting in this PR? for outboxStatus event, since it's emitted one or more times, you can just make sure the expectation is fulfilled without failing on overfulfillment. the other two (subscriptionsEstblished and synQueriesStarted) it should probably be just a single count each |
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/OutboxStatusEvent.swift
Outdated
Show resolved
Hide resolved
AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/Events/SyncQueriesStartedEvent.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Outdated
Show resolved
Hide resolved
...re/AWSDataStoreCategoryPluginIntegrationTests/TestSupport/HubEventsIntegrationTestBase.swift
Show resolved
Hide resolved
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Outdated
Show resolved
Hide resolved
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Outdated
Show resolved
Hide resolved
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Outdated
Show resolved
Hide resolved
Are there any unit tests that you can improve or add?
|
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Outdated
Show resolved
Hide resolved
...fyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/DataStoreHubEventsTests.swift
Show resolved
Hide resolved
Amplify/Categories/DataStore/DataStoreCategory+HubPayloadEventName.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
...SDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/OutgoingMutationQueue.swift
Outdated
Show resolved
Hide resolved
…t need to work on testing outboxStatus Received when MutationEvent finish processing
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.
looks good to me, question about naming for outboxStatus
. Should we stick with JS/Android or if we should stick to something more common in iOS like outgoingMutationStatus
?
@lawmicha We need to keep the names the same for platform consistency. We can revisit naming, event dispatch rules, payloads, etc in the future. |
@@ -23,4 +23,15 @@ public extension HubPayload.EventName.DataStore { | |||
/// Dispatched when DataStore receives a sync response from the remote API via the API category. The Hub Payload | |||
/// will be a `MutationEvent` instance that caused the conditional save failed. | |||
static let conditionalSaveFailed = "DataStore.conditionalSaveFailed" | |||
|
|||
/// Dispatched on DataStore start and also every time a local mutation is enqueued and processed in the outbox |
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.
Clarify wording: "Dispatched when: 1) the DataStore starts; 2) each time a local mutation is enqueued into the outbox; 3) each time a local mutation is finished processing."
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.
Updated
/// HubPayload `OutboxStatusEvent` contains a boolean value `isEmpty` to notify if there are mutations in the outbox | ||
static let outboxStatus = "DataStore.outboxStatus" | ||
|
||
/// Dispatched when all of the subscriptions to syncable models have been established |
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.
"Dispatched when DataStore has finished establishing its subscriptions to all syncable models"
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.
Updated
/// Dispatched when all of the subscriptions to syncable models have been established | ||
static let subscriptionsEstablished = "DataStore.subscriptionEstablished" | ||
|
||
/// Dispatched when DataStore is about to start sync queries |
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.
"Dispatched when DataStore starts establishing its subscriptions to all syncable models"
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.
For syncQueriesStarted
, it is not Dispatched when DataStore starts establishing its subscriptions to all syncable models
but is Dispatched when DataStore starts to sync Queries
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation |
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.
Unnecessary import
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.
Removed
|
||
/// Used as HubPayload for the `OutboxStatus` | ||
public struct OutboxStatusEvent { | ||
/// status of outbox: empty or not |
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.
"true
if there are no events in the outbox at the time the event was dispatched
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation |
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.
Unnecessary import
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.
Removed
|
||
/// Used as HubPayload for the `SyncQueriesStarted` | ||
public struct SyncQueriesStartedEvent { | ||
/// list of model names |
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.
"A list of all model names for which DataStore has started establishing subscriptions"
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.
Updated
case .success(let events): | ||
self.dispatchOutboxStatusEvent(isEmpty: events.isEmpty) | ||
case .failure(let error): | ||
log.error("Error quering mutation events: \(error)") |
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.
s/quering/querying/
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.
updated
@@ -241,10 +245,36 @@ final class OutgoingMutationQueue: OutgoingMutationQueueBehavior { | |||
self.log.verbose("mutationEvent deleted successfully") | |||
} | |||
|
|||
self.dispatchOutboxStatusEvent(isEmpty: true) |
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.
How do you know the outbox is empty here? Shouldn't you be querying the mutation events from storage, or checking the operationCount
of the outbox's operation queue?
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.
Right, it makes sense.
Incorrectly, I thought because subscription.request(.max(1))
ensure the queue to have only one mutationEvent
at a time so I can assert queue is empty when the event is finish processing. I miss the fact that events are stored inside the mutationEventDatabase.
Updated.
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.
As i understand it, we were emitting outboxStatus events to this logic (this is probably wrong then)
- when the remote sync engine starts, check if there are mutation events from storage to determine
isEmpty
- when a mutationEvent is being enqueued, we get this from the mutationEventPublisher, one mutationEvent at a time. hardcode
isEmpty
to false since we know we are processing one - when the mutationEvent is done being processed, we emit a following
outboxStatus
event withisEmpty = true
example output
outBoxStatus - isEmpty = false - on start, check mutationEvent from storage, say there 5 mutation events
outboxStatus - isEmpty = false - queue mutationEvent 1
outboxStatus - isEmpty = true - finish processing mutationEvent 1
outboxStatus - isEmpty = false - queue mutationEvent 2
outboxStatus - isEmpty = true - finish processing mutationEvent 2
outboxStatus - isEmpty = false - queue mutationEvent 3
outboxStatus - isEmpty = true - finish processing mutationEvent 3
outboxStatus - isEmpty = false - queue mutationEvent 4
outboxStatus - isEmpty = true - finish processing mutationEvent 4
outboxStatus - isEmpty = false - queue mutationEvent 5
outboxStatus - isEmpty = true - finish processing mutationEvent 5
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.
or is the expected behavior just a ping of the outbox status? for example
outBoxStatus - isEmpty = false - on start, check mutationEvent from storage, say there 5 mutation events
outboxStatus - isEmpty = false - queue mutationEvent 1
outboxStatus - isEmpty = false - finish processing mutationEvent 1
outboxStatus - isEmpty = false - queue mutationEvent 2
outboxStatus - isEmpty = false - finish processing mutationEvent 2
outboxStatus - isEmpty = false - queue mutationEvent 3
outboxStatus - isEmpty = false - finish processing mutationEvent 3
outboxStatus - isEmpty = false - queue mutationEvent 4
outboxStatus - isEmpty = false - finish processing mutationEvent 4
outboxStatus - isEmpty = false - queue mutationEvent 5
outboxStatus - isEmpty = true - finish processing mutationEvent 5
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.
@lawmicha the second behavior is the expected one.
For reference, this is the JS implementation:
It checks the queue
Issue #, if available:
The rest of 6 events will be implemented in other PRs.
Network Status
modelSynced
syncQueriesReady
ready
outboxMutationEnqueued
outboxMutationProcessed
Description of changes:
Implemented three of nine hub events
outboxStatus
syncQueriesStarted
subscriptionEstablished
outboxStatus
subscriptionsEstablished
When all subscriptions have been established, 3 per model, for every model, then emit a single subscriptionsEstablished event
syncQueriesStarted
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.