implemented a lot of features
This commit is contained in:
1 parent
62f1767df3
commit
bcb9be5da9
141 files changed
+10705
-385
No files matched your search
@@ -0,0 +1,45 @@
|
||||
import { setTimeout as sleep } from 'node:timers/promises'
|
||||
|
||||
/** After a signal, give cleanup this long before exiting anyway. */
|
||||
const FORCE_EXIT_MS = 25_000
|
||||
|
||||
/**
|
||||
* Graceful shutdown for the long-running commands. SIGTERM (docker stop) and
|
||||
* SIGINT wake up `wait()` and `sleep()`, so workers can finish their active
|
||||
* jobs and close their connections before the process exits.
|
||||
*/
|
||||
class Shutdown {
|
||||
private readonly controller = new AbortController()
|
||||
|
||||
constructor() {
|
||||
for (const signal of ['SIGTERM', 'SIGINT'] as const) {
|
||||
process.once(signal, () => {
|
||||
this.controller.abort()
|
||||
setTimeout(() => process.exit(0), FORCE_EXIT_MS).unref()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
get requested(): boolean {
|
||||
return this.controller.signal.aborted
|
||||
}
|
||||
|
||||
/** Resolves when a shutdown signal arrives. */
|
||||
wait(): Promise<void> {
|
||||
if (this.requested) return Promise.resolve()
|
||||
return new Promise((resolve) =>
|
||||
this.controller.signal.addEventListener('abort', () => resolve(), { once: true })
|
||||
)
|
||||
}
|
||||
|
||||
/** Sleeps, but returns early on shutdown. */
|
||||
async sleep(ms: number): Promise<void> {
|
||||
try {
|
||||
await sleep(ms, undefined, { signal: this.controller.signal })
|
||||
} catch {
|
||||
// aborted by a shutdown signal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Shutdown()
|
||||
Reference in new issue
Block a user