Skip to content

Commit 6a72bba

Browse files
committed
perf(files): coalesce concurrent renders of the same missing artifact
An artifact miss is identical for every concurrent reader — a freshly forked workspace whose document several viewers open at once, or one request whose blocks read the same file — and each was paying for its own compile of the same bytes. Share one in-flight render per (workspace, source, ext) key and drop the entry as soon as it settles, so a later read still re-renders normally.
1 parent c2214f0 commit 6a72bba

2 files changed

Lines changed: 60 additions & 8 deletions

File tree

apps/sim/lib/copilot/tools/server/files/doc-compile.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,27 @@ function compiledCacheSet(key: string, buffer: Buffer): void {
502502
*/
503503
const unrenderableSources = new Set<string>()
504504

505+
/**
506+
* Renders in flight, keyed identically to {@link compiledDocCache}. An artifact
507+
* miss is the same for every concurrent reader — a freshly forked workspace whose
508+
* document several viewers open at once, or one request whose blocks read the same
509+
* file — and rendering is the expensive step, so they share one run instead of each
510+
* paying for it. The entry is dropped as soon as the render settles, so a later read
511+
* re-renders normally rather than replaying a stale result.
512+
*/
513+
const inFlightRenders = new Map<string, Promise<{ buffer: Buffer; contentType: string }>>()
514+
515+
function coalesceRender(
516+
key: string,
517+
run: () => Promise<{ buffer: Buffer; contentType: string }>
518+
): Promise<{ buffer: Buffer; contentType: string }> {
519+
const existing = inFlightRenders.get(key)
520+
if (existing) return existing
521+
const started = run().finally(() => inFlightRenders.delete(key))
522+
inFlightRenders.set(key, started)
523+
return started
524+
}
525+
505526
function markUnrenderable(key: string): void {
506527
if (unrenderableSources.size >= MAX_COMPILED_DOC_CACHE) {
507528
unrenderableSources.delete(unrenderableSources.values().next().value as string)
@@ -624,7 +645,7 @@ export async function resolveServableDocBytes(args: {
624645
// (content-addressed), so racing a still-running write-time compile is wasteful
625646
// but correct.
626647
try {
627-
return await compileDoc({ source, fileName, workspaceId })
648+
return await coalesceRender(renderKey, () => compileDoc({ source, fileName, workspaceId }))
628649
} catch (error) {
629650
// Only a script error is deterministic — the same bytes will never render, so
630651
// remembering that is safe. Infra failures (sandbox create/timeout, S3, an
@@ -646,13 +667,15 @@ export async function resolveServableDocBytes(args: {
646667
}
647668

648669
try {
649-
const compiled = await runSandboxTask(
650-
format.taskId,
651-
{ code: source, workspaceId: workspaceId || '' },
652-
{ ownerKey, signal }
653-
)
654-
compiledCacheSet(renderKey, compiled)
655-
return { buffer: compiled, contentType: format.contentType }
670+
return await coalesceRender(renderKey, async () => {
671+
const compiled = await runSandboxTask(
672+
format.taskId,
673+
{ code: source, workspaceId: workspaceId || '' },
674+
{ ownerKey, signal }
675+
)
676+
compiledCacheSet(renderKey, compiled)
677+
return { buffer: compiled, contentType: format.contentType }
678+
})
656679
} catch (error) {
657680
// Unlike the E2B engine, the isolated-vm task does not distinguish a script
658681
// error from an infra one, so the only signal available here is cancellation —

apps/sim/lib/copilot/tools/server/files/doc-servable.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,35 @@ describe('resolveServableDocBytes', () => {
137137
expect(result.contentType).toBe('application/octet-stream')
138138
})
139139

140+
it('coalesces concurrent reads of the same missing artifact into one render', async () => {
141+
// A freshly forked workspace can have several viewers open the same document at
142+
// once; each would otherwise pay for its own compile of identical bytes.
143+
const source = uniqueSource('from reportlab.pdfgen import canvas')
144+
mockLoadCompiledDoc.mockResolvedValue(null)
145+
setEnvFlags({ isDocSandboxEnabled: true })
146+
mockExecuteInSandbox.mockImplementation(
147+
() =>
148+
new Promise((resolve) =>
149+
setTimeout(
150+
() => resolve({ exportedFileContent: Buffer.from('%PDF-once').toString('base64') }),
151+
5
152+
)
153+
)
154+
)
155+
156+
const args = { rawBuffer: source, fileName: 'report.pdf', workspaceId: WORKSPACE_ID }
157+
const [a, b, c] = await Promise.all([
158+
resolveServableDocBytes(args),
159+
resolveServableDocBytes(args),
160+
resolveServableDocBytes(args),
161+
])
162+
163+
expect(mockExecuteInSandbox).toHaveBeenCalledTimes(1)
164+
expect(a.buffer.toString()).toBe('%PDF-once')
165+
expect(b.buffer.toString()).toBe('%PDF-once')
166+
expect(c.buffer.toString()).toBe('%PDF-once')
167+
})
168+
140169
it('does not re-run the sandbox for bytes that already failed to render', async () => {
141170
const notReallyAPdf = uniqueSource('<html>still not a pdf</html>')
142171
mockLoadCompiledDoc.mockResolvedValue(null)

0 commit comments

Comments
 (0)