Keep native collection launches responsive

This commit is contained in:
2026-10-05 10:48:38 -04:00
parent dbd2940d29
commit 1405114a14
26 changed files with 998 additions and 123 deletions
+62
View File
@@ -0,0 +1,62 @@
import { setImmediate } from 'node:timers/promises';
import { getHostOperationPayload, type OperationDeliveryRow } from './index.js';
// Even non-ASCII content stays below 64 KiB per encoded chunk.
const CHUNK_CHARACTERS = 16 * 1024;
const CHUNK_BYTES = 64 * 1024;
const encoder = new TextEncoder();
function* jsonParts(operations: OperationDeliveryRow[], serverTime: string): Generator<string | Buffer> {
yield '{"operations":[';
for (const [index, operation] of operations.entries()) {
if (index) yield ',';
const metadata = JSON.stringify({
id: operation.id, hostId: operation.host_id, kind: operation.kind,
instanceId: operation.instance_id, generation: operation.generation, state: operation.state,
error: operation.error, createdAt: operation.created_at, updatedAt: operation.updated_at
});
yield metadata.slice(0, -1) + ',"payload":';
// Load only the immutable payload currently being sent, after the
// stream has yielded its metadata and had a chance to serve health work.
yield getHostOperationPayload(operation.host_id, operation.id);
yield ',"result":';
yield operation.result ?? 'null';
yield '}';
}
yield '],"serverTime":' + JSON.stringify(serverTime) + '}';
}
function* encodedChunks(operations: OperationDeliveryRow[], serverTime: string): Generator<Uint8Array> {
for (const part of jsonParts(operations, serverTime)) {
if (Buffer.isBuffer(part)) {
for (let start = 0; start < part.length; start += CHUNK_BYTES) yield part.subarray(start, start + CHUNK_BYTES);
continue;
}
for (let start = 0; start < part.length;) {
let end = Math.min(start + CHUNK_CHARACTERS, part.length);
// A UTF-16 surrogate pair must be encoded together, including when
// user-authored configuration text falls on a chunk boundary.
const last = part.charCodeAt(end - 1);
if (end < part.length && last >= 0xd800 && last <= 0xdbff) end--;
yield encoder.encode(part.slice(start, end));
start = end;
}
}
}
/** Bound encoding work and yield between chunks so health requests keep flowing. */
export function hostOperationsResponse(operations: OperationDeliveryRow[], serverTime = new Date().toISOString()): Response {
const chunks = encodedChunks(operations, serverTime);
let cancelled = false;
const stream = new ReadableStream<Uint8Array>({
async pull(controller) {
await setImmediate();
if (cancelled) return;
const next = chunks.next();
if (next.done) controller.close();
else controller.enqueue(next.value);
},
cancel() { cancelled = true; chunks.return(undefined); }
});
return new Response(stream, { headers: { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store' } });
}