Some more feedback
Opened this issue · 4 comments
- Wouldn’t use “stupid” here but rather “naive” or “unsafe”
effect-crashcourse/005-scope.ts
Line 87 in be233fa
- “trivial” or “pointless” rather than “stupid”:
effect-crashcourse/006-layer.ts
Line 36 in be233fa
- The following bit seems a bit out of place and unclear. Might be better to remove or move to next section. Could also maybe be rephrased if it’s meant to serve as a transition to next section
effect-crashcourse/005-scope.ts
Line 188 in be233fa
SIGINT and SIGTERM would be more appropriate here:
effect-crashcourse/006-layer.ts
Line 123 in be233fa
this gist gives a nice overview of various node events related to process shutting down:
https://gist.github.com/hyrious/30a878f6e6a057f09db87638567cb11a
this gist gives a nice overview of various node events related to process shutting down
TIL! (I'm new to Node)
I used beforeExit
because that's the only one that handles promises IIRC. I wonder how I would integrate async code with the other handlers.
I did address your suggestions. Still unsure how to go about the beforeExit
issue.
I used
beforeExit
because that's the only one that handles promises IIRC. I wonder how I would integrate async code with the other handlers.
You can execute async code from handlers of any the other events. Node will not exit for as long as there are any events on the event loop, so things like open sockets or active timeouts (created with for example setTimeout or setInterval), which usually accompany async code will keep the process alive, even if it received a signal trekking it to exit. The idea of a signal handler is to close all sockets, stop timers etc so that the process can exit by itself.
Here’s a piece of code I’ve been using (in non-effect apps) to handle signals:
export const wireSignalHandlers = (
nodeProcess: NodeProcessForSignalHandler,
onShutdown: AppStopFunction,
timeoutMs: number,
): void => {
// Wrapping with R.once since we could get both singnal in quick succesion
// but we only want this fuction to be called once.
const onSignal = R.once((signal: string) => {
// eslint-disable-next-line no-param-reassign, functional/immutable-data
nodeProcess.exitCode = 0
// Kill the process if not exited gracefully within timeout period.
setTimeout(
() => {
const error = new Error(
`Killing process after timeout of ${timeoutMs} ms from receiving `
+ `signal: ${signal}`,
)
logger.error(error)
// NOTE: do not call process.exit() anywhere else in the code base.
nodeProcess.exit(1)
},
timeoutMs,
)
// Make sure this timeout doesn’t prevent node from exiting
.unref()
Promise
.resolve(onShutdown()?.then(() => {}))
.catch(handleUnknownError(nodeProcess, logger))
})
signals.forEach(signal => nodeProcess.once(signal, onSignal))
}
The above would be called from a function similar to runMain from effect.