Skip to content

Commit 1dc2e45

Browse files
committed
remove hotpath serialiazation
1 parent 41384df commit 1dc2e45

6 files changed

Lines changed: 104 additions & 22 deletions

File tree

apps/sim/executor/orchestrators/loop.test.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ function createContext(scope: Record<string, unknown>): ExecutionContext {
3737
} as ExecutionContext
3838
}
3939

40-
function createOrchestrator() {
40+
function createOrchestrator(loopConfigs = new Map<string, any>()) {
4141
const setBlockOutput = vi.fn()
4242
const orchestrator = new LoopOrchestrator(
43-
{ loopConfigs: new Map(), parallelConfigs: new Map(), nodes: new Map() } as any,
43+
{ loopConfigs, parallelConfigs: new Map(), nodes: new Map() } as any,
4444
{ setBlockOutput, unmarkExecuted: vi.fn() } as any,
4545
{ resolveSingleReference: vi.fn() } as any
4646
)
@@ -75,6 +75,28 @@ describe('LoopOrchestrator', () => {
7575
})
7676
})
7777

78+
it('does not treat doWhile iterations of zero as an immediate configured cap', async () => {
79+
const { orchestrator } = createOrchestrator(
80+
new Map([
81+
[
82+
'loop-1',
83+
{
84+
loopType: 'doWhile',
85+
iterations: 0,
86+
doWhileCondition: 'true',
87+
nodes: ['block-1'],
88+
},
89+
],
90+
])
91+
)
92+
const ctx = createContext({})
93+
94+
const scope = await orchestrator.initializeLoopScope(ctx, 'loop-1')
95+
96+
expect(scope.maxIterations).toBeUndefined()
97+
expect(scope.condition).toBe('true')
98+
})
99+
78100
it('compacts current iteration outputs before retaining them', async () => {
79101
const { orchestrator, setBlockOutput } = createOrchestrator()
80102
const ctx = createContext({

apps/sim/executor/orchestrators/loop.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export class LoopOrchestrator {
163163

164164
case 'doWhile': {
165165
scope.loopType = 'doWhile'
166-
if (loopConfig.iterations !== undefined) {
166+
if (loopConfig.iterations) {
167167
scope.maxIterations = loopConfig.iterations
168168
}
169169
if (loopConfig.doWhileCondition) {

apps/sim/lib/execution/payloads/large-array-manifest-metadata.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,8 @@ function isValidByteSize(value: unknown): value is number {
2929
return typeof value === 'number' && Number.isFinite(value) && value >= 0
3030
}
3131

32-
function measureJsonSize(value: unknown): number | undefined {
33-
try {
34-
const json = JSON.stringify(value)
35-
return json === undefined ? undefined : new TextEncoder().encode(json).length
36-
} catch {
37-
return undefined
38-
}
39-
}
40-
4132
function isValidPreview(value: unknown): value is unknown[] {
42-
if (!Array.isArray(value) || value.length > 3) {
43-
return false
44-
}
45-
46-
const size = measureJsonSize(value)
47-
return size !== undefined && size <= LARGE_ARRAY_MANIFEST_PREVIEW_MAX_BYTES
33+
return Array.isArray(value) && value.length <= 3
4834
}
4935

5036
export function isLargeArrayManifest(value: unknown): value is LargeArrayManifest {

apps/sim/lib/execution/payloads/large-array-manifest.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,17 @@ describe('large array manifests', () => {
167167
)
168168
})
169169

170-
it('rejects manifests with oversized preview metadata', async () => {
170+
it('does not serialize preview metadata during hot type-guard checks', async () => {
171171
const manifest = await createLargeArrayManifest([{ id: 1 }], TEST_CONTEXT)
172+
const stringifySpy = vi.spyOn(JSON, 'stringify')
172173

173174
expect(
174175
isLargeArrayManifest({
175176
...manifest,
176177
preview: [{ payload: 'x'.repeat(20 * 1024) }],
177178
})
178-
).toBe(false)
179+
).toBe(true)
180+
expect(stringifySpy).not.toHaveBeenCalled()
181+
stringifySpy.mockRestore()
179182
})
180183
})

apps/sim/lib/execution/payloads/serializer.test.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
getLargeValueMaterializationError,
1212
isLargeValueRef,
1313
} from '@/lib/execution/payloads/large-value-ref'
14-
import { compactExecutionPayload } from '@/lib/execution/payloads/serializer'
14+
import { compactExecutionPayload, compactSubflowResults } from '@/lib/execution/payloads/serializer'
1515
import type { UserFile } from '@/executor/types'
1616

1717
const TEST_EXECUTION_CONTEXT = {
@@ -150,6 +150,77 @@ describe('compactExecutionPayload', () => {
150150
expect(isLargeValueRef(compacted)).toBe(true)
151151
})
152152

153+
it('bounds oversized manifest preview metadata during compaction', async () => {
154+
const forgedManifest = {
155+
__simLargeArrayManifest: true,
156+
version: LARGE_ARRAY_MANIFEST_VERSION,
157+
kind: 'array',
158+
totalCount: 1,
159+
chunkCount: 1,
160+
byteSize: 1,
161+
chunks: [
162+
{
163+
ref: {
164+
__simLargeValueRef: true,
165+
version: 1,
166+
id: 'lv_ABCDEFGHIJKL',
167+
kind: 'array',
168+
size: 1,
169+
executionId: TEST_EXECUTION_CONTEXT.executionId,
170+
},
171+
count: 1,
172+
byteSize: 1,
173+
},
174+
],
175+
preview: [{ payload: 'x'.repeat(20 * 1024) }],
176+
}
177+
178+
expect(isLargeArrayManifest(forgedManifest)).toBe(true)
179+
180+
const compacted = await compactExecutionPayload(forgedManifest, {
181+
thresholdBytes: 128,
182+
preserveRoot: true,
183+
...TEST_EXECUTION_CONTEXT,
184+
})
185+
186+
expect(isLargeValueRef(compacted)).toBe(true)
187+
})
188+
189+
it('does not re-wrap manifests when forcing oversized subflow result entries', async () => {
190+
const manifest = {
191+
__simLargeArrayManifest: true,
192+
version: LARGE_ARRAY_MANIFEST_VERSION,
193+
kind: 'array',
194+
totalCount: 1,
195+
chunkCount: 1,
196+
byteSize: 1,
197+
chunks: [
198+
{
199+
ref: {
200+
__simLargeValueRef: true,
201+
version: 1,
202+
id: 'lv_ABCDEFGHIJKL',
203+
kind: 'array',
204+
size: 1,
205+
executionId: TEST_EXECUTION_CONTEXT.executionId,
206+
},
207+
count: 1,
208+
byteSize: 1,
209+
},
210+
],
211+
preview: [],
212+
}
213+
const thresholdBytes = Buffer.byteLength(JSON.stringify(manifest), 'utf8') + 8
214+
215+
const compacted = await compactSubflowResults([manifest, manifest], {
216+
thresholdBytes,
217+
...TEST_EXECUTION_CONTEXT,
218+
})
219+
220+
expect(compacted).toEqual([manifest, manifest])
221+
expect(compacted.every(isLargeArrayManifest)).toBe(true)
222+
})
223+
153224
it('rejects durable compaction when storage context is incomplete', async () => {
154225
await expect(
155226
compactExecutionPayload(

apps/sim/lib/execution/payloads/serializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ async function forceStoreValue(
114114
value: unknown,
115115
options: CompactExecutionPayloadOptions
116116
): Promise<unknown> {
117-
if (isLargeValueRef(value)) {
117+
if (isLargeValueRef(value) || isLargeArrayManifest(value)) {
118118
return value
119119
}
120120
const measured = getJsonAndSize(value)

0 commit comments

Comments
 (0)