From 38c0d4a2bc51bf7f4a0da05df9a5c6e9b1da3a76 Mon Sep 17 00:00:00 2001 From: Kyle Hubert Date: Sun, 6 Jun 2021 23:41:42 -0400 Subject: [PATCH] Async iterable Endpoint handlers have back pressure Apply back pressure by pausing invocations of endpoint handler when part of the written data was queued in user memory. Once the kernel buffer is free to be written again, invocations will commence again. --- packages/adapter-node/src/server.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/adapter-node/src/server.js b/packages/adapter-node/src/server.js index 5158249b43e4..a9749e31485f 100644 --- a/packages/adapter-node/src/server.js +++ b/packages/adapter-node/src/server.js @@ -57,9 +57,24 @@ export function createServer({ render }) { typeof rendered.body[Symbol.asyncIterator] === 'function' ) { const flush = compressible(rendered.headers['content-type']) ? res.flush : null; + const drainers = []; + const writer = (event) => + new Promise((resolve) => { + if (!res.write(event)) { + drainers.push(resolve); + } else { + resolve(); + } + }); + // FIXME: upstream bug in compression prevents usage + // of res.once('drain', resolve) in writer's curry. + // https://github.com/expressjs/compression/pull/153 + res.on('drain', () => { + drainers.splice(0, drainers.length).forEach((resolve) => resolve()); + }); for await (const event of rendered.body) { if (res.connection.destroyed) break; - res.write(event); + await writer(event); flush?.(); } res.end();