A simple state machine for managing a service that asynchronously starts and stops.
npm install start-stop-state-machine
const StateMachine = require('start-stop-state-machine')
async function startService() {
console.log('starting')
await new Promise((res) => setTimeout(res, 200))
console.log('started')
}
async function stopService() {
console.log('stopping')
await new Promise((res) => setTimeout(res, 200))
console.log('stopped')
}
const sm = new StateMachine({ start: startService, stop: stopService })
;(async () => {
sm.start()
sm.start()
await sm.started()
// logs "starting" then "started", but only once
await sm.stop()
// lots "stopping", then "stopped"
})()
Type: ({value: Exclude<ServiceStateValue, "error"
>} | {value: "error"
, error: Error})
Type: Object
Extends TypedEmitter
A state machine for managing a service that has asynchronous "start" and
"stop" methods. Create an instance passing async opts.start()
and
opts.stop()
methods. It manages state following some basic rules:
- Most importantly: You can call start() and stop() multiple times, but the
service will end in the state of the last call (e.g. if the last call was
to
stop()
then it will end up stopped) - Calling
start()
when the service is "stopped" calls theopts.start()
method and resolves when it completes. - Calling
start()
when the service is "starting" (e.g.start()
has been called but has not completed) will not callopts.start()
again, but will resolve once the service has started - Calling
start()
when the service is "started" will resolve immediately and do nothing. - If
opts.start()
oropts.stop()
throw, then the service is left in an unrecoverable "error" state. - Calling
start()
orstop()
when the service is in "error" state will throw with the error from the error state
Logic for calling stop()
follows the inverse of start()
.
To wait for the service to be in the "started" state from other methods, use
await stateMachine.started()
. Note that if the services is "stopping" or
"stopped" then this will await (e.g. queue) until next start
-
opts
Object? (optional, default{}
)opts.start
(optional, defaultasync()=>{}
)opts.stop
(optional, defaultasync()=>{}
)
Get the current state of the service.
Returns ServiceState
Will resolve when the service is in started state. E.g. to ensure an async method only runs when the service is in "started" state, use:
await this.started()
Will reject if the service is in "error" state.
Note: If the service is in "stopping" or "stopped" state this will queue until the next time the service starts. If this is not desirable behaviour, check this.#state.value first
Returns Promise<void>
Will resolve when the service is in stopped state. Less useful than
started()
E.g. to ensure an async method only runs when the service is in
"stopped" state, use:
await this.stopped()
Will reject if the service is in "error" state.
Note: If the service is in "starting" or "started" state this will queue until the next time the service stops. If this is not desirable behaviour, check this.#state.value first
Returns Promise<void>
Start service. If the service is starting or started, will resolve when the service is started, and will not call opts.start() for than once. If the service is in the process of stopping, will wait until it stops before starting and will not call opts.stop() more than once
args
TStartArgs
Returns Promise<void> Resolves when service is started
Stop the service.
args
TStopArgs
Returns Promise<void>
Type: ServiceState
Type: TypedEmitter<InternalEvents>
PRs accepted.
Small note: If editing the README, please conform to the standard-readme specification.
MIT © 2022 Digital Democracy