Maintains a replicated state machine (RSM) with other RaftController instances in the Coaty network using the Raft protocol. For that each RaftController joins a specified Raft cluster. An instance of the RSM in form of a RaftStateMachine has to be provided in the RaftControllerOptions when bootstrapping this controller.

A new RaftController instance needs to connect() to the Raft cluster before it can modify/access the replicated state with the following functions:

  • propose(input) proposes a new input that should be applied to the RSM.
  • getState() returns the state of the RSM.
  • observeState() returns an observable emitting on every RSM change.

After a RaftController has connected to the Raft cluster it can monitor the cluster configuration with the following functions:

  • getClusterConfiguration() returns the cluster configuration.
  • observeClusterConfiguration() returns an observable emitting on every cluster configuration change.

Before shutting down the Coaty container of this RaftController the user has to either disconnect() from the Raft cluster or stop() this controller.

Hierarchy

  • Controller
    • RaftController

Raft

  • Connects this RaftController to the Raft cluster. Users of this RaftController need to wait til the returned promise is resolved before they can propose inputs with propose(...), observe the replicated state with getState() and observeState(), and monitor the cluster configuration with getClusterConfiguration() and observeClusterConfiguration().

    If this function is called after a crash and this RaftController was connected to the Raft cluster before the crash, persisted data will be used to restore this controller and reconnect to the Raft cluster.

    Returns Promise<void>

    A promise that resolves once this RaftController has connected to the Raft cluster.

    Remarks

    The RaftController with shouldCreateCluster set to true will create a new Raft cluster on initial startup. Trying to connect a RaftController with this option set to false will only resolve after a Raft cluster has been created and a majority of the existing cluster has agreed on letting this RaftController join.

    Throws

    An InvalidControllerOptionsError if the RaftControllerOptions provided when bootstrapping this controller are invalid or missing.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is currently in the process of disconnecting or stopping.

  • Disconnects this RaftController from the Raft cluster therefore removing it from the cluster configuration. Users of this RaftController need to wait til the returned promise is resolved before they can shutdown the corresponding Coaty container. Deletes all persisted state of this controller. The shared state of a Raft cluster is lost after all RaftControllers of that cluster have disconnected.

    Returns Promise<void>

    A promise that resolves once this RaftController has disconnected.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is currently in the process of connecting or stopping.

  • Returns a promise resolving to the cluster configuration. The cluster configuration contains the ids of all RaftControllers in the cluster.

    Returns Promise<string[]>

    A promise resolving to the cluster configuration. The cluster configuration contains the ids of all RaftControllers in the cluster.

    Remark

    The returned configuration is guaranteed to be up to date or newer respective to the point in time when this function was called. In other words calling getClusterConfiguration() at time t will return the cluster configuration from some point in time inside [t, ∞]. This means that all connects and disconnects that finished before t are guaranteed to already be applied in this configuration. Newer connects and disconnects that finished after t might also already be applied.

    Throws

    A DisconnectBeforeOperationCompleteError if this controller disconnected before the cluster configuration could be retrieved.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is not connected to the Raft cluster, this.connect() needs to be called first.

  • Returns a promise resolving to the state of the RSM. The state is retrieved by proposing a NOOP and waiting for its resulting state. The NOOP is being proposed internally and therefore cannot be observed by observeState().

    Returns Promise<any>

    A promise resolving to the state of the RSM. The state will be of type RaftData.

    Remark

    The returned state is guaranteed to be up to date or newer respective to the point in time when this function was called. In other words calling getState() at time t will return the distributed state from some point in time inside [t, ∞]. This means that all inputs committed before t are guaranteed to already be applied in this state. Newer inputs that were committed after t might also already be applied.

    Throws

    A DisconnectBeforeOperationCompleteError if this controller is disconnected from the cluster before the state could be retrieved.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is not connected to the Raft cluster, this.connect() needs to be called first.

  • Returns an observable that emits the cluster configuration on every configuration change as soon as the change becomes known to this controller. Cluster configuration changes are triggered when a RaftController connects to or disconnects from the Raft cluster.

    The returned observable completes and its subscriptions are automatically unsubscribed once the controller is disconnected or stopped, in order to release system resources and to avoid memory leaks.

    Returns Observable<string[]>

    an observable emitting the cluster configuration on every configuration change. The cluster configuration contains the ids of all RaftControllers in the cluster.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is not connected to the Raft cluster, this.connect() needs to be called first.

  • Returns an observable that emits the state of the RSM on every state update as soon as the update becomes known to this controller. State updates are triggered when a new input is committed.

    The returned observable completes and its subscriptions are automatically unsubscribed once the controller is disconnected or stopped, in order to release system resources and to avoid memory leaks.

    Returns Observable<any>

    an observable emitting the state of the RSM on every state update. The emitted state will be of type RaftData.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is not connected to the Raft cluster, this.connect() needs to be called first.

  • Proposes the given input to Raft. Raft will try to add the input to a log shared between all RaftControllers in the Raft cluster. If the input is accepted into the log it counts as committed and is applied to the RSM. The returned promise resolves to the resulting state of the RSM after the proposed input has been applied.

    A majority of controllers need to give their consent before the given input is accepted into the log. This might take indefinitely if no majority can be reached, e.g. if too many agents have crashed and cannot recover. In this case the returned promise is never resolved or rejected.

    Parameters

    • input: any

      Input that should be committed and applied to the RSM. Has to be of type RaftData.

    Returns Promise<any>

    A promise resolving to the resulting state of the RSM after the proposed input has been applied if it ever gets applied. Is of type RaftData. Is rejected if this RaftController is stopped or disconnected before it could make sure that the input was committed. The input might still be committed.

    Remark

    This function implements reproposed inputs as explained inside the Raft thesis. Manual reproposing by the user is not intended. That is why the returned promise never times out.

    Remark

    The object structure of input and resulting state can be chosen by the user and depends on the implementation of the RSM that is provided in the RaftControllerOptions of this controller. Both input and resulting state have to be of type RaftData.

    Throws

    A TooManyQueuedUpInputProposalsError if there are more than 1000 input proposals queued up that haven't been committed yet.

    Throws

    A DisconnectBeforeOperationCompleteError if this controller is disconnected from the cluster before it could make sure that the proposed input was committed.

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is not connected to the Raft cluster, this.connect() needs to be called first.

  • Stops this RaftController WITHOUT disconnecting from the Raft cluster and WITHOUT deleting the persisted state. Users of this RaftController need to wait til the returned promise is resolved before they can shutdown the corresponding Coaty container.

    Users can use this function instead of disconnect() if they want to shutdown this controller for some time without losing the current shared state and cluster configuration. This might be useful if e.g. the entire cluster has to shutdown for a few days but its state and configuration should be preserved. stop() can also be seen as a graceful crash.

    Returns Promise<void>

    A promise that resolves once this RaftController has been stopped.

    Remark

    If at least half of all RaftControllers in the Raft cluster are stopped the cluster can no longer make any progress til enough stopped controllers reconnect using connect().

    Throws

    An OperationNotSupportedInCurrentConnectionStateError if this controller is currently in the process of connecting or disconnecting.

Raft Interfaces

  • Can be overwritten to change the RaftPersistency implementation used by Raft.

    The default implementation persists Raft data using Coaty's SQL-based local storage in the form of a local SQLite database file. This database must be referenced in Coaty Configuration.databaseOptions under the key specified by RaftControllerOptions.databaseKey (or "raftdb" if not specified) using the adapter named "SqLiteNodeAdapter". Make sure the path to the database file (i.e. connectionString) exists and is accessible.

    Returns RaftPersistency

Uncategorized

  • Internal

    For internal use in framework only.

    Never instantiate Controller objects in your application; they are created automatically by dependency injection.

    Parameters

    • _container: Container
    • _options: ControllerOptions
    • _controllerName: string

    Returns RaftController

  • get communicationManager(): CommunicationManager
  • Gets the container's communication manager.

    Returns CommunicationManager

  • get container(): Container
  • Gets the container object of this controller.

    Returns Container

  • get options(): Readonly<ControllerOptions>
  • Gets the controller's options as specified in the configuration options.

    Returns Readonly<ControllerOptions>

  • get registeredName(): string
  • Gets the registered name of this controller.

    The registered name is either defined by the corresponding key in the Components.controllers object in the container configuration, or by invoking Container.registerController method with this name.

    Returns string

  • get runtime(): Runtime
  • Gets the container's Runtime object.

    Returns Runtime

  • Whenever one of the controller's log methods (e.g. logDebug, logInfo, logWarning, logError, logFatal) is called by application code, the controller creates a Log object with appropriate property values and passes it to this method before advertising it.

    You can override this method to additionally set certain properties (such as LogHost.hostname or Log.logLabels). Ensure that super.extendLogObject is called in your override. The base method does nothing.

    Parameters

    • log: Log

      log object to be extended before being advertised

    Returns void

  • Advertise a Log object for debugging purposes.

    Parameters

    • message: string

      a debug message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Advertise a Log object for an error.

    Parameters

    • error: any

      an error (object)

    • message: string

      additional error message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Advertise a Log object for an error with stacktrace information.

    Parameters

    • error: any

      an error (object)

    • message: string

      additional error message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Advertise a Log object for a fatal error.

    Parameters

    • error: any

      an error (object)

    • message: string

      additional error message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Advertise an informational Log object.

    Parameters

    • message: string

      an informational message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Advertise a Log object for a warning.

    Parameters

    • message: string

      a warning message

    • Rest ...tags: string[]

      any number of log tags

    Returns void

  • Called when the communication manager is about to start or restart.

    Override this method to implement side effects here. Ensure that super.onCommunicationManagerStarting is called in your override. The base implementation does nothing.

    Returns void

  • Called when the communication manager is about to stop.

    Override this method to implement side effects here. Ensure that super.onCommunicationManagerStopping is called in your override. The base implementation does nothing.

    Returns void

  • Called by the container when this instance should be disposed.

    Implement cleanup side effects here. Ensure that super.onDispose is called in your override. The base implementation does nothing.

    Returns void

  • Called when the container has completely set up and injected all dependency components, including all its controllers.

    Override this method to perform initializations in your custom controller class instead of defining a constructor. Although the base implementation does nothing it is good practice to call super.onInit() in your override method; especially if your custom controller class does not extend from the base Controller class directly.

    Returns void

Generated using TypeDoc