diff --git a/rivetkit-typescript/packages/rivetkit/src/registry/index.ts b/rivetkit-typescript/packages/rivetkit/src/registry/index.ts
index 3617ff7094..97243c9fa1 100644
--- a/rivetkit-typescript/packages/rivetkit/src/registry/index.ts
+++ b/rivetkit-typescript/packages/rivetkit/src/registry/index.ts
@@ -13,6 +13,22 @@ import type { RuntimeServerlessResponseHead } from "./runtime";
type ShutdownSignal = "SIGINT" | "SIGTERM";
+function signalExitCode(signal: ShutdownSignal): number {
+ switch (signal) {
+ case "SIGINT":
+ return 130;
+ case "SIGTERM":
+ return 143;
+ }
+}
+
+function finishShutdownSignal(signal: ShutdownSignal): void {
+ if (process.pid === 1) {
+ process.exit(signalExitCode(signal));
+ }
+ process.kill(process.pid, signal);
+}
+
export type FetchHandler = (
request: Request,
...args: any
@@ -452,10 +468,11 @@ export class Registry {
): void {
if (this.#shutdownInFlight !== null) {
// Second delivery of the same (or another) shutdown signal.
- // Remove our handler only (preserving any user-installed listeners)
- // and re-raise so Node proceeds with its default exit path.
+ // Remove our handler only, preserving any user-installed listeners.
+ // PID 1 must exit directly because re-raised default signals can be
+ // swallowed by the container signal path.
this.#removeSignalHandlers();
- process.kill(process.pid, signal);
+ finishShutdownSignal(signal);
return;
}
this.#shutdownInFlight = this.#runShutdown(
@@ -530,7 +547,7 @@ export class Registry {
),
]);
this.#removeSignalHandlers();
- process.kill(process.pid, signal);
+ finishShutdownSignal(signal);
}
#removeSignalHandlers(): void {