Archived
1
0

Provide a way to tell when event handlers are finished

This lets us actually wait for disposal before a graceful exit.
This commit is contained in:
Asher 2020-11-04 16:49:01 -06:00
parent 396af23842
commit 8252c372af
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
3 changed files with 26 additions and 7 deletions

View File

@ -1,4 +1,10 @@
import { Callback } from "./types" import { logger } from "@coder/logger"
/**
* Event emitter callback. Called with the emitted value and a promise that
* resolves when all emitters have finished.
*/
export type Callback<T, R = void | Promise<void>> = (t: T, p: Promise<void>) => R
export interface Disposable { export interface Disposable {
dispose(): void dispose(): void
@ -32,8 +38,21 @@ export class Emitter<T> {
/** /**
* Emit an event with a value. * Emit an event with a value.
*/ */
public emit(value: T): void { public async emit(value: T): Promise<void> {
this.listeners.forEach((cb) => cb(value)) let resolve: () => void
const promise = new Promise<void>((r) => (resolve = r))
await Promise.all(
this.listeners.map(async (cb) => {
try {
await cb(value, promise)
} catch (error) {
logger.error(error.message)
}
}),
)
resolve!()
} }
public dispose(): void { public dispose(): void {

View File

@ -1 +0,0 @@
export type Callback<T, R = void> = (t: T) => R

View File

@ -39,13 +39,14 @@ export class IpcMain {
process.on("SIGTERM", () => this._onDispose.emit("SIGTERM")) process.on("SIGTERM", () => this._onDispose.emit("SIGTERM"))
process.on("exit", () => this._onDispose.emit(undefined)) process.on("exit", () => this._onDispose.emit(undefined))
this.onDispose((signal) => { this.onDispose((signal, wait) => {
// Remove listeners to avoid possibly triggering disposal again. // Remove listeners to avoid possibly triggering disposal again.
process.removeAllListeners() process.removeAllListeners()
// Let any other handlers run first then exit. // Try waiting for other handlers run first then exit.
logger.debug(`${parentPid ? "inner process" : "wrapper"} ${process.pid} disposing`, field("code", signal)) logger.debug(`${parentPid ? "inner process" : "wrapper"} ${process.pid} disposing`, field("code", signal))
setTimeout(() => this.exit(0), 0) wait.then(() => this.exit(0))
setTimeout(() => this.exit(0), 5000)
}) })
// Kill the inner process if the parent dies. This is for the case where the // Kill the inner process if the parent dies. This is for the case where the