Skip to content

Commit

Permalink
enhance(server): improvements on automatic disposal
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Nov 25, 2024
1 parent d3d3f64 commit b4ab548
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 40 deletions.
6 changes: 6 additions & 0 deletions .changeset/eleven-bees-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@whatwg-node/server': patch
---

Remove SIGTERM from termination events to prevent hangs, and always add disposable stack to the termination events

67 changes: 28 additions & 39 deletions packages/server/src/createServerAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,40 +101,28 @@ function createServerAdapter<
const onRequestHooks: OnRequestHook<TServerContext & ServerAdapterInitialContext>[] = [];
const onResponseHooks: OnResponseHook<TServerContext & ServerAdapterInitialContext>[] = [];
const waitUntilPromises = new Set<PromiseLike<unknown>>();
const disposableStack = new AsyncDisposableStack();
const signals = new Set<ServerAdapterRequestAbortSignal>();

function registerSignal(signal: ServerAdapterRequestAbortSignal) {
signals.add(signal);
signal.addEventListener('abort', () => {
signals.delete(signal);
});
}

disposableStack.defer(() => {
for (const signal of signals) {
signal.sendAbort();
}
});

disposableStack.defer(() => {
if (waitUntilPromises.size > 0) {
return Promise.allSettled(waitUntilPromises).then(
() => {
waitUntilPromises.clear();
},
() => {
waitUntilPromises.clear();
},
);
let _disposableStack: AsyncDisposableStack | undefined;
function ensureDisposableStack() {
if (!_disposableStack) {
_disposableStack = new AsyncDisposableStack();
ensureDisposableStackRegisteredForTerminateEvents(_disposableStack);
_disposableStack.defer(() => {
if (waitUntilPromises.size > 0) {
return Promise.allSettled(waitUntilPromises).then(
() => {
waitUntilPromises.clear();
},
() => {
waitUntilPromises.clear();
},
);
}
});
}
});
return _disposableStack;
}

function waitUntil(promiseLike: PromiseLike<unknown>) {
// If it is a Node.js environment, we should register the disposable stack to handle process termination events
if (globalThis.process) {
ensureDisposableStackRegisteredForTerminateEvents(disposableStack);
}
waitUntilPromises.add(promiseLike);
promiseLike.then(
() => {
Expand All @@ -157,7 +145,7 @@ function createServerAdapter<
}
const disposeFn = plugin[DisposableSymbols.asyncDispose] || plugin[DisposableSymbols.dispose];
if (disposeFn != null) {
disposableStack.defer(disposeFn);
ensureDisposableStack().defer(disposeFn);
}
}
}
Expand Down Expand Up @@ -244,7 +232,7 @@ function createServerAdapter<
// TODO: Remove this on the next major version
function handleNodeRequest(nodeRequest: NodeRequest, ...ctx: Partial<TServerContext>[]) {
const serverContext = ctx.length > 1 ? completeAssign(...ctx) : ctx[0] || {};
const request = normalizeNodeRequest(nodeRequest, fetchAPI, registerSignal);
const request = normalizeNodeRequest(nodeRequest, fetchAPI);
return handleRequest(request, serverContext);
}

Expand Down Expand Up @@ -308,7 +296,6 @@ function createServerAdapter<
: defaultServerContext;

const signal = new ServerAdapterRequestAbortSignal();
registerSignal(signal);
const originalResEnd = res.end.bind(res);
let resEnded = false;
res.end = function (data: any) {
Expand Down Expand Up @@ -455,16 +442,18 @@ function createServerAdapter<
handleEvent,
handleUWS,
handle: genericRequestHandler as ServerAdapterObject<TServerContext>['handle'],
disposableStack,
get disposableStack() {
return ensureDisposableStack();
},
[DisposableSymbols.asyncDispose]() {
if (!disposableStack.disposed) {
return disposableStack.disposeAsync();
if (_disposableStack && !_disposableStack.disposed) {
return _disposableStack.disposeAsync();
}
return fakePromise(undefined);
},
dispose() {
if (!disposableStack.disposed) {
return disposableStack.disposeAsync();
if (_disposableStack && !_disposableStack.disposed) {
return _disposableStack.disposeAsync();
}
return fakePromise(undefined);
},
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ export function handleResponseDecompression(response: Response, fetchAPI: FetchA
return decompressedResponse;
}

const terminateEvents = ['SIGINT', 'SIGTERM', 'exit'] as const;
const terminateEvents = ['SIGINT', 'exit'] as const;
const disposableStacks = new Set<AsyncDisposableStack>();

let eventListenerRegistered = false;
Expand Down

0 comments on commit b4ab548

Please sign in to comment.