Skip to content

Commit 7e17692

Browse files
committed
fix(file-parsers): drain queued jobs on worker start failure, ship bundle under dist
1 parent 7533745 commit 7e17692

7 files changed

Lines changed: 24 additions & 8 deletions

File tree

‎apps/sim/lib/file-parsers/xlsx-worker-entry.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Worker-thread entry for spreadsheet parsing, bundled to
3-
* `lib/file-parsers/dist/xlsx-worker.mjs` by `bun run build:xlsx-worker` and
3+
* `apps/sim/dist/xlsx-worker.mjs` by `bun run build:xlsx-worker` and
44
* spawned by `xlsx-worker-pool.ts`. It runs the same {@link XlsxParser} the
55
* main thread falls back to, so the two paths cannot drift.
66
*/

‎apps/sim/lib/file-parsers/xlsx-worker-pool.test.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* 1. Worker output diverges from in-process parsing (preview, complete).
77
* 2. A typed parser error loses its class, `code`, or message crossing back.
88
* 3. A missing bundle breaks parsing instead of falling back in-process.
9-
* 4. An unloadable bundle (throws at load) breaks parsing instead of falling back.
9+
* 4. An unloadable bundle (throws at load, or the Worker constructor itself
10+
* throws) breaks parsing or strands queued jobs instead of falling back.
1011
* 5. A worker crash mid-parse loses the job instead of re-running it in-process.
1112
* 6. An abort during a worker parse hangs or leaves the worker occupying its slot.
1213
* 7. An abort while queued still dispatches the job.
@@ -151,6 +152,19 @@ describe('XlsxWorkerPool fallback', () => {
151152
await expect(pool.parse(input, {}, inProcess(input))).resolves.toEqual(expected)
152153
})
153154

155+
it('parses every queued job in-process when the Worker constructor throws', async () => {
156+
const input = workbook()
157+
const expected = await parser.parseBuffer(input)
158+
const pool = new XlsxWorkerPool({ workerPath: 'not-a-resolvable-worker-path.mjs', size: 1 })
159+
160+
const results = await Promise.all([
161+
pool.parse(input, {}, inProcess(input)),
162+
pool.parse(input, {}, inProcess(input)),
163+
])
164+
165+
expect(results).toEqual([expected, expected])
166+
})
167+
154168
it('re-runs a job in-process when the worker dies mid-parse', async () => {
155169
const input = workbook()
156170
const expected = await parser.parseBuffer(input)

‎apps/sim/lib/file-parsers/xlsx-worker-pool.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const XLSX_WORKER_IDLE_TIMEOUT_MS = 30_000
2828
/** Bounds worker startup only; a parse itself is bounded by the caller's signal. */
2929
const XLSX_WORKER_START_TIMEOUT_MS = 10_000
3030

31-
const WORKER_BUNDLE_RELATIVE_PATH = path.join('lib', 'file-parsers', 'dist', 'xlsx-worker.mjs')
31+
const WORKER_BUNDLE_RELATIVE_PATH = path.join('dist', 'xlsx-worker.mjs')
3232

3333
/**
3434
* Where `bun run build:xlsx-worker` writes the bundle, as seen from the two
@@ -257,6 +257,7 @@ export class XlsxWorkerPool {
257257
this.retire(slot)
258258
if (job) this.runInProcess(job)
259259
}
260+
for (const job of this.queue.splice(0)) this.runInProcess(job)
260261
}
261262

262263
private runInProcess(job: Job): void {

‎apps/sim/lib/file-parsers/xlsx-worker-protocol.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { FileParseOptions, FileParseResult } from '@/lib/file-parsers/types
1111
* throw is encoded by kind and rebuilt as the same class on the main side.
1212
*/
1313

14-
export type XlsxWorkerParseOptions = Omit<FileParseOptions, 'signal'>
14+
type XlsxWorkerParseOptions = Omit<FileParseOptions, 'signal'>
1515

1616
export interface XlsxWorkerParseRequest {
1717
type: 'parse'

‎apps/sim/next.config.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ const nextConfig: NextConfig = {
163163
*/
164164
'/*': [
165165
'./lib/execution/sandbox/bundles/*.cjs',
166-
'./lib/file-parsers/dist/xlsx-worker.mjs',
166+
'./dist/xlsx-worker.mjs',
167167
'./node_modules/ws/**/*',
168168
'../../packages/sim-cli/dist/runtime.js',
169169
],

‎apps/sim/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"load:workflow:isolation": "BASE_URL=${BASE_URL:-http://localhost:3000} ISOLATION_DURATION=${ISOLATION_DURATION:-30} TOTAL_RATE=${TOTAL_RATE:-9} WORKSPACE_A_WEIGHT=${WORKSPACE_A_WEIGHT:-8} WORKSPACE_B_WEIGHT=${WORKSPACE_B_WEIGHT:-1} artillery run scripts/load/workflow-isolation.yml",
2020
"build": "bun run build:cli-runtime && bun run build:sandbox-bundles && bun run build:xlsx-worker && NODE_OPTIONS='--max-old-space-size=8192' next build",
2121
"build:sandbox-bundles": "bun run ./lib/execution/sandbox/bundles/build.ts",
22-
"build:xlsx-worker": "bun build ./lib/file-parsers/xlsx-worker-entry.ts --target=node --format=esm --packages=bundle --outfile=./lib/file-parsers/dist/xlsx-worker.mjs",
22+
"build:xlsx-worker": "bun build ./lib/file-parsers/xlsx-worker-entry.ts --target=node --format=esm --packages=bundle --outfile=./dist/xlsx-worker.mjs",
2323
"start": "next start",
2424
"test": "vitest run",
2525
"test:scim:e2e": "bun run scripts/test-scim-e2e.ts",

‎docker/app.Dockerfile‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,11 @@ COPY --from=deps --chown=nextjs:nodejs /app/node_modules/@napi-rs ./node_modules
213213
# Copy the isolated-vm worker script
214214
COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/lib/execution/isolated-vm-worker.cjs ./apps/sim/lib/execution/isolated-vm-worker.cjs
215215

216-
# Spreadsheet parse worker bundle (build:xlsx-worker, run by `bun run build`).
216+
# Spreadsheet parse worker bundle (build:xlsx-worker, run by `bun run build`;
217+
# under the build task's declared `dist/**` output so a Turbo cache hit restores it).
217218
# Without it parsing falls back in-process, so a missing file fails the image
218219
# build here instead of silently putting XLSX parsing back on the event loop.
219-
COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/lib/file-parsers/dist/xlsx-worker.mjs ./apps/sim/lib/file-parsers/dist/xlsx-worker.mjs
220+
COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/dist/xlsx-worker.mjs ./apps/sim/dist/xlsx-worker.mjs
220221

221222
# Copy the pre-built sandbox library bundles (pptxgenjs, docx, pdf-lib) that
222223
# run inside the V8 isolate. Committed into the repo; see

0 commit comments

Comments
 (0)