Skip to content

Commit c268b9e

Browse files
committed
fix(execution): tune the event offload threshold to the observed distribution
Set the buffered-event offload threshold from production data rather than the budget arithmetic alone. Across 111k executions, bytes-per-trace-span runs ~4.8 KB at p50, ~59 KB at p90 and ~960 KB at p99, and no execution came within 3 MB of the 64 MiB budget. 256 KiB sits between p90 and p99, so ordinary runs stay fully inline and only the outlier tail is offloaded — ~4% of executions, against ~9% at 64 KiB and ~15% at 32 KiB. Offloading costs fidelity: a ref renders as a 256-character preview, and for arrays and objects as a shape summary rather than contents. Tuning to the distribution keeps that off the 95% of runs that never threatened the budget.
1 parent 332657f commit c268b9e

2 files changed

Lines changed: 22 additions & 11 deletions

File tree

apps/sim/lib/execution/event-buffer.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ describe('execution event buffer', () => {
376376
it('offloads values far below the shared large-value threshold', async () => {
377377
mockRedis.incrby.mockResolvedValue(100)
378378
// Comfortably under LARGE_VALUE_THRESHOLD_BYTES (8 MiB), over the event one.
379-
const payload = 'x'.repeat(64 * 1024)
379+
const payload = 'x'.repeat(512 * 1024)
380380

381381
const writer = createExecutionEventWriter('exec-1', {
382382
workspaceId: 'ws-1',
@@ -387,7 +387,7 @@ describe('execution event buffer', () => {
387387

388388
expect(persistedEntries).toHaveLength(1)
389389
const persistedBytes = Buffer.byteLength(JSON.stringify(persistedEntries[0]), 'utf8')
390-
expect(persistedBytes).toBeLessThan(64 * 1024)
390+
expect(persistedBytes).toBeLessThan(256 * 1024)
391391
})
392392

393393
it('preserves requested UserFile base64 when buffering terminal events', async () => {

apps/sim/lib/execution/payloads/large-value-ref.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,28 @@ export const LARGE_VALUE_THRESHOLD_BYTES = 8 * 1024 * 1024
66
* Offload threshold for values inlined into buffered execution events.
77
*
88
* The replay buffer keeps `EVENT_LIMIT` (1000) events per execution inside a
9-
* `MAX_EXECUTION_REDIS_BYTES` (64 MiB) budget, so a full ring buffer only fits
10-
* if events average under 64 KiB. Anything above that exhausts the budget
11-
* before the ring even fills and pins the run at its ceiling for the rest of
12-
* its life. This sits at half that ceiling because the budget counts a whole
13-
* event while the threshold caps one value, and an event can carry several.
9+
* `MAX_EXECUTION_REDIS_BYTES` (64 MiB) budget. Values were offloaded at 8 MiB,
10+
* so a run emitting large block outputs exhausted that budget within a few
11+
* dozen events and stayed pinned at its ceiling for the rest of its life.
1412
*
15-
* Deliberately far below {@link LARGE_VALUE_THRESHOLD_BYTES}, which stays at
16-
* 8 MiB for executor snapshots and inline UserFile base64 — those are bounded
17-
* per payload rather than accumulated across a thousand of them.
13+
* Chosen from the observed distribution of bytes-per-trace-span across 111k
14+
* production executions: p50 ~4.8 KB, p90 ~59 KB, p99 ~960 KB. This sits 4x
15+
* above p90 and 4x below p99, so ordinary runs stay fully inline and only the
16+
* outlier tail — the shape that exhausts the budget — is offloaded. It applies
17+
* to ~4% of executions, against ~9% at 64 KiB and ~15% at 32 KiB.
18+
*
19+
* Offloading is not free: a ref renders in the terminal as a 256-character
20+
* string preview, or for arrays and objects as a shape summary rather than
21+
* their contents. That cost is why this tracks the real distribution instead of
22+
* the 64 KiB the budget arithmetic alone would suggest — no execution in that
23+
* sample came within 3 MB of the budget.
24+
*
25+
* Deliberately separate from {@link LARGE_VALUE_THRESHOLD_BYTES}, which stays
26+
* at 8 MiB for executor snapshots and inline UserFile base64. Those are bounded
27+
* per payload rather than accumulated across a thousand of them, and the base64
28+
* limit is derived from it arithmetically.
1829
*/
19-
export const EXECUTION_EVENT_VALUE_THRESHOLD_BYTES = 32 * 1024
30+
export const EXECUTION_EVENT_VALUE_THRESHOLD_BYTES = 256 * 1024
2031
export const LARGE_VALUE_REF_VERSION = 1
2132

2233
export const LARGE_VALUE_KINDS = ['array', 'object', 'string', 'json'] as const

0 commit comments

Comments
 (0)