Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/eleven-moose-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@opennextjs/aws": patch
---

fix(dev-overrides): Add automatic response cleanup via onClose callback

This changes will make `request.signal.onabort` work in route handlers for `node` and `express-dev` wrappers.
8 changes: 8 additions & 0 deletions packages/open-next/src/http/openNextResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ export class OpenNextNodeResponse extends Transform implements ServerResponse {
) {
this.statusCode = statusCode;
}

// We want to destroy this response when the original response is closed. (i.e when the client disconnects)
// This is to support `request.signal.onabort` in route handlers
if (streamCreator?.abortSignal) {
streamCreator.abortSignal.addEventListener("abort", () => {
this.destroy();
});
}
}

// Necessary for next 12
Expand Down
6 changes: 5 additions & 1 deletion packages/open-next/src/overrides/wrappers/cloudflare-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const handler: WrapperHandler<InternalEvent, InternalResult> =
request: Request,
env: Record<string, string>,
ctx: any,
abortSignal: AbortSignal,
): Promise<Response> => {
globalThis.process = process;

// Set the environment variables
// Cloudflare suggests to not override the process.env object but instead apply the values to it
for (const [key, value] of Object.entries(env)) {
Expand Down Expand Up @@ -66,6 +66,10 @@ const handler: WrapperHandler<InternalEvent, InternalResult> =

return Writable.fromWeb(writable);
},
// This is for passing along the original abort signal from the initial Request you retrieve in your worker
// Ensures that the response we pass to NextServer is aborted if the request is aborted
// By doing this `request.signal.onabort` will work in route handlers
abortSignal: abortSignal,
};

ctx.waitUntil(
Expand Down
9 changes: 9 additions & 0 deletions packages/open-next/src/overrides/wrappers/express-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const wrapper: WrapperHandler = async (handler, converter) => {
req.headers["x-forwarded-proto"] = req.protocol;
}
const internalEvent = await converter.convertFrom(req);

const abortController = new AbortController();

const streamCreator: StreamCreator = {
writeHeaders: (prelude) => {
res.setHeader("Set-Cookie", prelude.cookies);
Expand All @@ -49,7 +52,13 @@ const wrapper: WrapperHandler = async (handler, converter) => {
return res;
},
onFinish: () => {},
abortSignal: abortController.signal,
};

res.on("close", () => {
abortController.abort();
});

await handler(internalEvent, { streamCreator });
});

Expand Down
13 changes: 12 additions & 1 deletion packages/open-next/src/overrides/wrappers/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,32 @@ import { debug, error } from "../../adapters/logger";
const wrapper: WrapperHandler = async (handler, converter) => {
const server = createServer(async (req, res) => {
const internalEvent = await converter.convertFrom(req);

const abortController = new AbortController();

const streamCreator: StreamCreator = {
writeHeaders: (prelude) => {
res.setHeader("Set-Cookie", prelude.cookies);
res.writeHead(prelude.statusCode, prelude.headers);
res.flushHeaders();
return res;
},
abortSignal: abortController.signal,
};

res.on("close", () => {
abortController.abort();
});

if (internalEvent.rawPath === "/__health") {
res.writeHead(200, {
"Content-Type": "text/plain",
});
res.end("OK");
} else {
await handler(internalEvent, { streamCreator });
await handler(internalEvent, {
streamCreator,
});
}
});

Expand Down
1 change: 1 addition & 0 deletions packages/open-next/src/types/open-next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface StreamCreator {
// Just to fix an issue with aws lambda streaming with empty body
onWrite?: () => void;
onFinish?: (length: number) => void;
abortSignal?: AbortSignal;
}

export type WaitUntil = (promise: Promise<void>) => void;
Expand Down
Loading