class WorkerPool { private workers: Worker[] = []; private availableWorkers: Worker[] = []; private queue: Array<{ file: File; resolve: (text: string) => void; reject: (error: Error) => void; }> = []; constructor(poolSize: number = 3) { // Pre-spawn workers for (let i = 0; i < poolSize; i++) { const worker = new Worker( new URL('./pdf.worker.ts', import.meta.url), { type: 'module' } ); this.workers.push(worker); this.availableWorkers.push(worker); } } async parse(file: File): Promise { // If worker available, use immediately if (this.availableWorkers.length > 0) { return this.parseWithWorker(file); } // Otherwise, queue the request return new Promise((resolve, reject) => { this.queue.push({ file, resolve, reject }); }); } private async parseWithWorker(file: File): Promise { const worker = this.availableWorkers.pop()!; try { const result = await this.executeParse(worker, file); return result; } finally { // Worker is done, make it available or process queue if (this.queue.length > 0) { const next = this.queue.shift()!; this.parseWithWorker(next.file) .then(next.resolve) .catch(next.reject); } else { this.availableWorkers.push(worker); } } } private executeParse(worker: Worker, file: File): Promise { return new Promise(async (resolve, reject) => { const buffer = await file.arrayBuffer(); const timeout = setTimeout(() => { reject(new Error('Worker timeout')); }, 30000); const cleanup = () => { clearTimeout(timeout); worker.removeEventListener('message', handleMessage); worker.removeEventListener('error', handleError); }; const handleMessage = (e: MessageEvent) => { if (e.data.error) { cleanup(); reject(new Error(e.data.error)); } else if (e.data.text) { cleanup(); resolve(e.data.text); } // Ignore progress messages }; const handleError = (err: ErrorEvent) => { cleanup(); reject(err); }; worker.addEventListener('message', handleMessage); worker.addEventListener('error', handleError); worker.postMessage({ buffer }, [buffer]); }); } terminate() { this.workers.forEach(w => w.terminate()); this.workers = []; this.availableWorkers = []; this.queue = []; } } // Usage const pool = new WorkerPool(3); // Multiple concurrent uploads async function handleUpload(file: File) { try { const text = await pool.parse(file); console.log('Parsed:', text); } catch (err) { console.error('Parse failed:', err); } } __ __