diff --git a/.changeset/honest-lamps-smell.md b/.changeset/honest-lamps-smell.md index 54278a33a..ce408f339 100644 --- a/.changeset/honest-lamps-smell.md +++ b/.changeset/honest-lamps-smell.md @@ -1,11 +1,8 @@ --- -"@opennextjs/aws": minor +"@opennextjs/aws": patch --- perf(OpenNextResponse): do not store the chunks for streamed responses There is no need to store the chunks for streamed responses. -Not storing the chunks allows saving memory. - -BREAKING CHANGE: Note that `OpenNextHandler` will now return an empty body if your wrapper provides a `StreamCreator` -This could break custom converters. +Not storing the chunks allows saving memory. \ No newline at end of file diff --git a/.changeset/warm-rats-crash.md b/.changeset/warm-rats-crash.md new file mode 100644 index 000000000..fb3b93c64 --- /dev/null +++ b/.changeset/warm-rats-crash.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +refactor(StreamCreator): allow opting-out of retaining the chunks diff --git a/packages/open-next/src/http/openNextResponse.ts b/packages/open-next/src/http/openNextResponse.ts index 45ff8425f..4a521e760 100644 --- a/packages/open-next/src/http/openNextResponse.ts +++ b/packages/open-next/src/http/openNextResponse.ts @@ -287,8 +287,8 @@ export class OpenNextNodeResponse extends Transform implements ServerResponse { private _internalWrite(chunk: any, encoding: BufferEncoding) { const buffer = Buffer.from(chunk, encoding); this.bodyLength += buffer.length; - if (!this.streamCreator) { - // Do not keep chunks around for streamed responses + if (this.streamCreator?.retainChunks !== false) { + // Avoid keeping chunks around when the `StreamCreator` supports it to save memory this._chunks.push(buffer); } this.push(chunk, encoding); diff --git a/packages/open-next/src/overrides/wrappers/cloudflare-node.ts b/packages/open-next/src/overrides/wrappers/cloudflare-node.ts index 1d6b8c10b..b3d8b374e 100644 --- a/packages/open-next/src/overrides/wrappers/cloudflare-node.ts +++ b/packages/open-next/src/overrides/wrappers/cloudflare-node.ts @@ -70,6 +70,8 @@ const handler: WrapperHandler = // 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, + // There is no need to retain the chunks that were pushed to the response stream. + retainChunks: false, }; ctx.waitUntil( diff --git a/packages/open-next/src/types/open-next.ts b/packages/open-next/src/types/open-next.ts index 74980874d..cbab1abc3 100644 --- a/packages/open-next/src/types/open-next.ts +++ b/packages/open-next/src/types/open-next.ts @@ -56,6 +56,18 @@ export interface StreamCreator { onWrite?: () => void; onFinish?: (length: number) => void; abortSignal?: AbortSignal; + /** + * Normally there is no need to retain the chunks that have been pushed to the response stream. + * + * However some implementations use a fake `StreamCreator` and expect the chunks to be retained. + * When your stream controller implementation doesn't need to retain the chunk, you can set this + * to `false` to reduce memory usage. + * + * @see https://github.com/opennextjs/opennextjs-aws/blob/main/packages/open-next/src/overrides/wrappers/aws-lambda.ts + * + * @default true for backward compatibility. + */ + retainChunks?: boolean; } export type WaitUntil = (promise: Promise) => void;