Skip to content

Commit 44c5be9

Browse files
authored
fix signal handling (#1460)
* fix signal handling * fix kill test
1 parent 1b71e52 commit 44c5be9

File tree

2 files changed

+23
-17
lines changed

2 files changed

+23
-17
lines changed

src/telemetry.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ export class Telemetry {
9797
this.disabled = !!process.env.OBSERVABLE_TELEMETRY_DISABLE;
9898
this.debug = !!process.env.OBSERVABLE_TELEMETRY_DEBUG;
9999
this.endpoint = new URL("/cli", getOrigin(process.env));
100-
process.on("SIGHUP", this.handleSignal(1));
101-
process.on("SIGINT", this.handleSignal(2));
102-
process.on("SIGTERM", this.handleSignal(15));
100+
this.handleSignal("SIGHUP");
101+
this.handleSignal("SIGINT");
102+
this.handleSignal("SIGTERM");
103103
}
104104

105105
record(data: TelemetryData) {
@@ -122,17 +122,23 @@ export class Telemetry {
122122
return Promise.all(this._pending);
123123
}
124124

125-
private handleSignal(value: number) {
126-
const code = 128 + value;
127-
return async (signal: NodeJS.Signals) => {
128-
const {process} = this.effects;
129-
// Give ourselves 1s to record a signal event and flush.
130-
const deadline = setTimeout(() => process.exit(code), 1000);
125+
private handleSignal(name: string) {
126+
const {process} = this.effects;
127+
let exiting = false;
128+
const signaled = async (signal: NodeJS.Signals) => {
129+
if (exiting) return; // already exiting
130+
exiting = true;
131131
this.record({event: "signal", signal});
132-
await this.pending;
133-
clearTimeout(deadline);
134-
process.exit(code);
132+
try {
133+
// Allow one second to record a signal event and flush.
134+
await Promise.race([this.pending, new Promise((resolve) => setTimeout(resolve, 1000))]);
135+
} catch {
136+
// ignore error
137+
}
138+
process.off(name, signaled); // don’t handle our own kill
139+
process.kill(process.pid, signal);
135140
};
141+
process.on(name, signaled);
136142
}
137143

138144
private async getPersistentId(name: string, generator = randomUUID) {

test/telemetry-test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ describe("telemetry", () => {
104104
it("saves a signal record on exit", async () => {
105105
const logger = new MockLogger();
106106
const listeners = {};
107-
let exit: (value: unknown) => void;
108-
const exited = new Promise((resolve) => (exit = resolve));
107+
let kill: (value: unknown) => void;
108+
const killed = new Promise((resolve) => (kill = resolve));
109109
new Telemetry({
110110
...noopEffects,
111111
logger,
@@ -115,14 +115,14 @@ describe("telemetry", () => {
115115
listeners[event] = listener;
116116
return this;
117117
},
118-
exit(code?: number) {
119-
exit(code);
118+
kill(pid: number, signal?: string) {
119+
kill(signal);
120120
throw new Error("exit");
121121
}
122122
})
123123
});
124124
listeners["SIGINT"]("SIGINT");
125-
assert.equal(await exited, 130);
125+
assert.equal(await killed, "SIGINT");
126126
assert.equal(logger.errorLines.length, 1);
127127
assert.deepEqual(logger.errorLines[0][1].data, {event: "signal", signal: "SIGINT"});
128128
});

0 commit comments

Comments
 (0)