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

Add shutdown. #111

Merged
merged 4 commits into from
Nov 19, 2024
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# `@bedrock/core` ChangeLog

## 6.3.0 - 2024-xx-xx

### Added
- Add `bedrock.shutdown()` call that performs an orderly shutdown and emits
various events. This differs from `exit()` and `process.exit()` which are
more immediate.
- Add `bedrock.stopped` event, emitted before `bedrock.exit`.
- Add documentation for `bedrock.stop`, `bedrock.stopped`, and `bedrock.exit`
events.

### Changed
- Deprecate undocumented `bedrock-cli.exit` event. Use `bedrock.exit`. If there
is use case for this specific event, please file an issue.

## 6.2.0 - 2024-10-15

### Changed
Expand Down
35 changes: 24 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,19 +576,21 @@ all the `bedrock-cli` events, unless a listener cancels the `bedrock-cli.ready`
event or causes the application to exit early.

- **bedrock-cli.init**
- Emitted before command line parsing. Allows registration of new subcommands.
- Emitted before command line parsing. Allows registration of new
subcommands.
- **bedrock-cli.parsed**
- Emitted after command line parsing. Allows for configuration of loggers
based on command line flags. For instance, a logger may provide for the
specification of a `logGroupName` that may be computed at runtime based
on some command line flag(s).
specification of a `logGroupName` that may be computed at runtime based on
some command line flag(s).
- **bedrock-loggers.init**
- Emitted after command line parsing. Allows registration of new logging
transports prior to initialization of the logging subsystem.
- **bedrock-cli.ready**
- Emitted after command line parsing and logging initialization. Allows
execution of subcommands or the prevention of `bedrock` events from being
emitted, either by canceling this event or by exiting the application early.
emitted, either by canceling this event or by exiting the application
early.
- **bedrock.configure**
- Emitted after `bedrock-cli.ready` and before `bedrock.admin.init`. Allows
additional custom configuration before Bedrock initializes but after
Expand All @@ -605,17 +607,17 @@ event or causes the application to exit early.
- **bedrock.init**
- Emitted after `bedrock.admin.init` and just after elevated process
privileges are dropped. Allows listeners to perform early initialization
tasks that do not require special privileges. This event should be used
to ensure, for example, that a module's API has the required supporting
data structures in memory prior to another module's use of it. For example,
a validation module may need to load validation schemas from files on disk
tasks that do not require special privileges. This event should be used to
ensure, for example, that a module's API has the required supporting data
structures in memory prior to another module's use of it. For example, a
validation module may need to load validation schemas from files on disk
before they can be accessed via its API, but this loading must occur after
the configuration events have passed and after special process privileges
have been dropped. **As a best practice, modules should not emit custom
events during `bedrock.init` because it may cause scenarios where two
unrelated modules can't be easily combined.** For example, if a module emits
a custom event during `bedrock.init`, then a listener of that event would
be unable to use the API of an unrelated module that hasn't been
unrelated modules can't be easily combined.** For example, if a module
emits a custom event during `bedrock.init`, then a listener of that event
would be unable to use the API of an unrelated module that hasn't been
initialized yet. Deferring custom event emitting to `bedrock.start` solves
this problem; it ensures all modules have had a chance to complete
initialization before attempting to interact with one another through the
Expand All @@ -642,6 +644,17 @@ event or causes the application to exit early.
`false` to indicate to the test subsystem that at least one test did not
pass. Test frameworks may add their own information to the state object
using a property matching their framework name.
- **bedrock.stop**
- Emitted while exiting if process was previous in a started state. This is
the event modules should use to stop services for a clean shutdown and to
emit any custom events they would like to make available to their
dependents.
- **bedrock.stopped**
- Emitted while exiting, and after `bedrock.stop` if process was previously
in a started state. External access to web services or other features
provided by modules should now be unavailable.
- **bedrock.exit**
- Emitted immediately before exiting.

### bedrock.loggers

Expand Down
33 changes: 23 additions & 10 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,24 @@
}

/**
* Called from a worker to exit gracefully and without an error code. Typically
* used by subcommands. Use `process.exit(1)` (or other error code) to exit
* with an error code.
* Called from a worker to exit immediately and without an error code.
* Typically used by subcommands. Use `process.exit(1)` (or other error code)
* to exit with an error code. Use `shutdown` to perform an orderly exit.
*/
export function exit() {
cluster.worker.kill();
}

/**
* Called from a worker to exit gracefully and without an error code. Typically
* used by subcommands. Use `process.exit(1)` (or other error code) to exit
* with an error code. Use `exit()` to exit immediately. This call will emit
* events for an orderly shutdown.
*/
export async function shutdown() {
await _exit();
}

Check warning on line 253 in lib/index.js

View check run for this annotation

Codecov / codecov/patch

lib/index.js#L252-L253

Added lines #L252 - L253 were not covered by tests

async function _waitForOneMessage({type, id}) {
// get coordinated message from primary
return new Promise(resolve => {
Expand Down Expand Up @@ -720,7 +730,7 @@
}
}

async function _exit(code) {
async function _exit(code = 0) {
/* Notes on exiting:

When the primary does an orderly exit, it must notify all workers
Expand Down Expand Up @@ -754,12 +764,18 @@
if(BEDROCK_STARTED) {
await events.emit('bedrock.stop');
}
await events.emit('bedrock.stopped');
// FIXME: deprecated in v6.x, remove in v7+

Check warning on line 768 in lib/index.js

View check run for this annotation

Codecov / codecov/patch

lib/index.js#L767-L768

Added lines #L767 - L768 were not covered by tests
await events.emit('bedrock-cli.exit');
await events.emit('bedrock.exit');
}
} finally {
await _logExit(code);
process.exit(code);
if(cluster.isPrimary) {
await _logExit(code);
process.exit(code);
} else {
cluster.worker.kill();
}

Check warning on line 778 in lib/index.js

View check run for this annotation

Codecov / codecov/patch

lib/index.js#L777-L778

Added lines #L777 - L778 were not covered by tests
}
}

Expand All @@ -770,10 +786,7 @@
}
}

async function _logExit(code = 0) {
if(!cluster.isPrimary) {
return;
}
async function _logExit(code) {
// log final message and wait for logger to flush
const logger = loggers.get('app').child('bedrock/primary');
try {
Expand Down