From 8252c372af84d8f5d2de40674af5eeda96e387e6 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 4 Nov 2020 16:49:01 -0600 Subject: [PATCH] Provide a way to tell when event handlers are finished This lets us actually wait for disposal before a graceful exit. --- src/common/emitter.ts | 25 ++++++++++++++++++++++--- src/common/types.ts | 1 - src/node/wrapper.ts | 7 ++++--- 3 files changed, 26 insertions(+), 7 deletions(-) delete mode 100644 src/common/types.ts diff --git a/src/common/emitter.ts b/src/common/emitter.ts index 7a1ebf66..353ce851 100644 --- a/src/common/emitter.ts +++ b/src/common/emitter.ts @@ -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: T, p: Promise) => R export interface Disposable { dispose(): void @@ -32,8 +38,21 @@ export class Emitter { /** * Emit an event with a value. */ - public emit(value: T): void { - this.listeners.forEach((cb) => cb(value)) + public async emit(value: T): Promise { + let resolve: () => void + const promise = new Promise((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 { diff --git a/src/common/types.ts b/src/common/types.ts deleted file mode 100644 index a8a0e4c1..00000000 --- a/src/common/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type Callback = (t: T) => R diff --git a/src/node/wrapper.ts b/src/node/wrapper.ts index cce84190..2e8c51cd 100644 --- a/src/node/wrapper.ts +++ b/src/node/wrapper.ts @@ -39,13 +39,14 @@ export class IpcMain { process.on("SIGTERM", () => this._onDispose.emit("SIGTERM")) process.on("exit", () => this._onDispose.emit(undefined)) - this.onDispose((signal) => { + this.onDispose((signal, wait) => { // Remove listeners to avoid possibly triggering disposal again. 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)) - 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