diff --git a/gitnexus/src/core/ingestion/workers/worker-pool.ts b/gitnexus/src/core/ingestion/workers/worker-pool.ts index bc23f0ea41..9fa77ef399 100644 --- a/gitnexus/src/core/ingestion/workers/worker-pool.ts +++ b/gitnexus/src/core/ingestion/workers/worker-pool.ts @@ -24,6 +24,7 @@ export interface WorkerPool { /** Message shapes sent back by worker threads. */ type WorkerOutgoingMessage = | { type: 'progress'; filesProcessed: number } + | { type: 'warning'; message: string } | { type: 'sub-batch-done' } | { type: 'error'; error: string } | { type: 'result'; data: unknown }; @@ -120,6 +121,8 @@ export const createWorkerPool = (workerUrl: URL, poolSize?: number): WorkerPool const total = workerProgress.reduce((a, b) => a + b, 0); onProgress(total); } + } else if (msg.type === 'warning') { + console.warn(msg.message); } else if (msg.type === 'sub-batch-done') { sendNextSubBatch(); } else if (msg.type === 'error') { diff --git a/gitnexus/test/integration/worker-pool.test.ts b/gitnexus/test/integration/worker-pool.test.ts index 48a7c506ac..072d9e24c1 100644 --- a/gitnexus/test/integration/worker-pool.test.ts +++ b/gitnexus/test/integration/worker-pool.test.ts @@ -6,11 +6,12 @@ * This is critical for cross-platform CI where vitest runs from src/ * but workers need compiled .js files. */ -import { describe, it, expect, afterEach } from 'vitest'; +import { describe, it, expect, afterEach, vi } from 'vitest'; import { createWorkerPool, WorkerPool } from '../../src/core/ingestion/workers/worker-pool.js'; import { pathToFileURL } from 'node:url'; import path from 'node:path'; import fs from 'node:fs'; +import os from 'node:os'; const DIST_WORKER = path.resolve( __dirname, @@ -185,6 +186,43 @@ describe('worker pool integration', () => { }, ); + it('treats warning messages as non-terminal and still resolves the worker result', async () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gitnexus-worker-warning-')); + const workerPath = path.join(tempDir, 'warning-worker.js'); + fs.writeFileSync( + workerPath, + ` + const { parentPort } = require('node:worker_threads'); + parentPort.on('message', (msg) => { + if (msg && msg.type === 'sub-batch') { + parentPort.postMessage({ type: 'warning', message: 'warning before result' }); + parentPort.postMessage({ type: 'sub-batch-done' }); + return; + } + if (msg && msg.type === 'flush') { + parentPort.postMessage({ type: 'result', data: { nodes: [], relationships: [], symbols: [], imports: [], calls: [], heritage: [], routes: [], fileCount: 1 } }); + } + }); + `, + ); + + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined); + const workerUrl = pathToFileURL(workerPath) as URL; + pool = createWorkerPool(workerUrl, 1); + + try { + const results = await pool.dispatch([ + { path: 'warning.ts', content: 'const x = 1;' }, + ]); + expect(results).toHaveLength(1); + expect(results[0].fileCount).toBe(1); + expect(warnSpy).toHaveBeenCalledWith('warning before result'); + } finally { + warnSpy.mockRestore(); + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); + it.skipIf(!hasDistWorker)('createWorkerPool with size 0 creates pool with zero workers', () => { const workerUrl = pathToFileURL(DIST_WORKER) as URL; const zeroPool = createWorkerPool(workerUrl, 0);