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

Update RemoteSyncEngine to adopt a StateMachine to allow for easier control of start/stop/retry #321

Merged
merged 1 commit into from
Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify
import Combine

@available(iOS 13.0, *)
extension RemoteSyncEngine {

/// Actions are declarative, they say what I just did
enum Action {
// Startup/config actions
case receivedStart

case pausedSubscriptions
case pausedMutationQueue(APICategoryGraphQLBehavior, StorageEngineAdapter)
case initializedSubscriptions
case performedInitialSync
case activatedCloudSubscriptions(APICategoryGraphQLBehavior, MutationEventPublisher)
case activatedMutationQueue
case notifiedSyncStarted

// Terminal actions
case receivedCancel
case errored(AmplifyError)

var displayName: String {
switch self {
case .receivedStart:
return "receivedStart"
case .pausedSubscriptions:
return "pausedSubscriptions"
case .pausedMutationQueue:
return "pausedMutationQueue"
case .initializedSubscriptions:
return "initializedSubscriptions"
case .performedInitialSync:
return "performedInitialSync"
case .activatedCloudSubscriptions:
return "activatedCloudSubscriptions"
case .activatedMutationQueue:
return "activatedMutationQueue"
case .notifiedSyncStarted:
return "notifiedSyncStarted"
case .receivedCancel:
return "receivedCancel"
case .errored:
return "errored"
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify
import Combine
import Foundation

@available(iOS 13.0, *)
extension RemoteSyncEngine {
@available(iOS 13.0, *)
func onReceiveCompletion(receiveCompletion: Subscribers.Completion<DataStoreError>) {
if case .failure(let error) = receiveCompletion {
wooj2 marked this conversation as resolved.
Show resolved Hide resolved
remoteSyncTopicPublisher.send(completion: .failure(error))
}
if case .finished = receiveCompletion {
let unexpectedFinishError = DataStoreError.unknown("ReconcilationQueue sent .finished message",
AmplifyErrorMessages.shouldNotHappenReportBugToAWS(),
nil)
remoteSyncTopicPublisher.send(completion: .failure(unexpectedFinishError))
}
}

@available(iOS 13.0, *)
func onReceive(receiveValue: IncomingEventReconciliationQueueEvent) {
switch receiveValue {
case .started:
remoteSyncTopicPublisher.send(.subscriptionsActivated)
if let api = self.api {
stateMachine.notify(action: .activatedCloudSubscriptions(api, mutationEventPublisher))
}
case .paused:
remoteSyncTopicPublisher.send(.subscriptionsPaused)
case .mutationEvent(let mutationEvent):
remoteSyncTopicPublisher.send(.mutationEvent(mutationEvent))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify
import Combine

@available(iOS 13.0, *)
extension RemoteSyncEngine {
struct Resolver {
static func resolve(currentState: State, action: Action) -> State {
switch (currentState, action) {
case (.notStarted, .receivedStart):
return .pauseSubscriptions

case (.pauseSubscriptions, .pausedSubscriptions):
return .pauseMutationQueue

case (.pauseMutationQueue, .pausedMutationQueue(let api, let storageEngineAdapter)):
return .initializeSubscriptions(api, storageEngineAdapter)

case (.initializeSubscriptions, .initializedSubscriptions):
return .performInitialSync

case (.performInitialSync, .performedInitialSync):
return .activateCloudSubscriptions
case (.performInitialSync, .errored(let error)):
return .cleanup(error)

case (.activateCloudSubscriptions, .activatedCloudSubscriptions(let api, let mutationEventPublisher)):
return .activateMutationQueue(api, mutationEventPublisher)
case (.activateCloudSubscriptions, .errored(let error)):
return .cleanup(error)

case (.activateMutationQueue, .activatedMutationQueue):
return .notifySyncStarted
case (.activateMutationQueue, .errored(let error)):
return .cleanup(error)

case (.notifySyncStarted, .notifiedSyncStarted):
return .syncEngineActive

default:
log.warn("Unexpected state transition. In \(currentState.displayName), got \(action.displayName)")
log.verbose("Unexpected state transition. In \(currentState), got \(action)")
return currentState
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify
import Combine
@available(iOS 13.0, *)
extension RemoteSyncEngine {

/// States are descriptive, they say what is happening in the system right now
enum State {
case notStarted

case pauseSubscriptions
case pauseMutationQueue
case initializeSubscriptions(APICategoryGraphQLBehavior, StorageEngineAdapter)
case performInitialSync
case activateCloudSubscriptions
case activateMutationQueue(APICategoryGraphQLBehavior, MutationEventPublisher)
case notifySyncStarted
wooj2 marked this conversation as resolved.
Show resolved Hide resolved

case syncEngineActive

case cleanup(AmplifyError)
var displayName: String {
switch self {
case .notStarted:
return "notStarted"
case .pauseSubscriptions:
return "pauseCloudSubscriptions"
case .pauseMutationQueue:
return "pauseMutationQueue"
case .initializeSubscriptions:
return "initializeSubscriptions"
case .performInitialSync:
return "performInitialSync"
case .activateCloudSubscriptions:
return "activateCloudSubscriptions"
case .activateMutationQueue:
return "activateMutationQueue"
case .notifySyncStarted:
return "notifySyncStarted"
case .syncEngineActive:
return "syncEngineActive"
case .cleanup:
return "cleanup"
}
}
}
}
Loading