Hotswap on SIGUSR1 (#1970)
This commit is contained in:
parent
3c90b1e327
commit
74910ffcdf
|
@ -32,7 +32,7 @@ export class IpcMain {
|
||||||
public readonly onMessage = this._onMessage.event
|
public readonly onMessage = this._onMessage.event
|
||||||
private readonly _onDispose = new Emitter<NodeJS.Signals | undefined>()
|
private readonly _onDispose = new Emitter<NodeJS.Signals | undefined>()
|
||||||
public readonly onDispose = this._onDispose.event
|
public readonly onDispose = this._onDispose.event
|
||||||
public readonly exit: (code?: number) => never
|
public readonly processExit: (code?: number) => never
|
||||||
|
|
||||||
public constructor(public readonly parentPid?: number) {
|
public constructor(public readonly parentPid?: number) {
|
||||||
process.on("SIGINT", () => this._onDispose.emit("SIGINT"))
|
process.on("SIGINT", () => this._onDispose.emit("SIGINT"))
|
||||||
|
@ -40,7 +40,7 @@ export class IpcMain {
|
||||||
process.on("exit", () => this._onDispose.emit(undefined))
|
process.on("exit", () => this._onDispose.emit(undefined))
|
||||||
|
|
||||||
// Ensure we control when the process exits.
|
// Ensure we control when the process exits.
|
||||||
this.exit = process.exit
|
this.processExit = process.exit
|
||||||
process.exit = function (code?: number) {
|
process.exit = function (code?: number) {
|
||||||
logger.warn(`process.exit() was prevented: ${code || "unknown code"}.`)
|
logger.warn(`process.exit() was prevented: ${code || "unknown code"}.`)
|
||||||
} as (code?: number) => never
|
} as (code?: number) => never
|
||||||
|
@ -71,6 +71,14 @@ export class IpcMain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public exit(error?: number | ProcessError): never {
|
||||||
|
if (error && typeof error !== "number") {
|
||||||
|
this.processExit(typeof error.code === "number" ? error.code : 1)
|
||||||
|
} else {
|
||||||
|
this.processExit(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public handshake(child?: cp.ChildProcess): Promise<void> {
|
public handshake(child?: cp.ChildProcess): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const target = child || process
|
const target = child || process
|
||||||
|
@ -161,28 +169,37 @@ export class WrapperProcess {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain().onMessage(async (message) => {
|
ipcMain().onMessage((message) => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case "relaunch":
|
case "relaunch":
|
||||||
logger.info(`Relaunching: ${this.currentVersion} -> ${message.version}`)
|
logger.info(`Relaunching: ${this.currentVersion} -> ${message.version}`)
|
||||||
this.currentVersion = message.version
|
this.currentVersion = message.version
|
||||||
this.started = undefined
|
this.relaunch()
|
||||||
if (this.process) {
|
|
||||||
this.process.removeAllListeners()
|
|
||||||
this.process.kill()
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await this.start()
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error.message)
|
|
||||||
ipcMain().exit(typeof error.code === "number" ? error.code : 1)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
logger.error(`Unrecognized message ${message}`)
|
logger.error(`Unrecognized message ${message}`)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
process.on("SIGUSR1", async () => {
|
||||||
|
logger.info("Received SIGUSR1; hotswapping")
|
||||||
|
this.relaunch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private async relaunch(): Promise<void> {
|
||||||
|
this.started = undefined
|
||||||
|
if (this.process) {
|
||||||
|
this.process.removeAllListeners()
|
||||||
|
this.process.kill()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.start()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message)
|
||||||
|
ipcMain().exit(typeof error.code === "number" ? error.code : 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): Promise<void> {
|
public start(): Promise<void> {
|
||||||
|
@ -244,13 +261,13 @@ export const wrap = (fn: () => Promise<void>): void => {
|
||||||
.then(() => fn())
|
.then(() => fn())
|
||||||
.catch((error: ProcessError): void => {
|
.catch((error: ProcessError): void => {
|
||||||
logger.error(error.message)
|
logger.error(error.message)
|
||||||
ipcMain().exit(typeof error.code === "number" ? error.code : 1)
|
ipcMain().exit(error)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const wrapper = new WrapperProcess(require("../../package.json").version)
|
const wrapper = new WrapperProcess(require("../../package.json").version)
|
||||||
wrapper.start().catch((error) => {
|
wrapper.start().catch((error) => {
|
||||||
logger.error(error.message)
|
logger.error(error.message)
|
||||||
ipcMain().exit(typeof error.code === "number" ? error.code : 1)
|
ipcMain().exit(error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue