All files / server/services pooled-compiler.ts

75% Statements 21/28
75% Branches 15/20
83.33% Functions 5/6
75% Lines 21/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                                                    15x     15x   15x 3x 12x                   12x                             138x 1x 1x 1x                     137x 1x   136x                             8x 1x   7x                           9x 1x               6x     1x 1x        
/**
 * Compilation Pool Adapter
 * 
 * Wraps the CompilationWorkerPool to provide the same interface
 * as the direct ArduinoCompiler, but routes work through worker threads.
 * 
 * In development mode (tsx), falls back to direct compilation because
 * worker threads don't have access to TypeScript path mappings (@shared/*).
 * In production (transpiled .js), uses worker pool for parallelization.
 * 
 * This allows minimal changes to existing code that expects a `compiler`
 * object with a `compile()` method.
 */
 
import { CompilationWorkerPool, getCompilationPool } from "./compilation-worker-pool";
import { ArduinoCompiler } from "./arduino-compiler";
import type { CompilationResult, CompileRequestOptions } from "./arduino-compiler";
import type { CompileRequestPayload } from "@shared/worker-protocol";
 
export class PooledCompiler {
  private readonly pool: CompilationWorkerPool | null;
  private readonly directCompiler: ArduinoCompiler;
  private readonly usePool: boolean;
 
  constructor(pool?: CompilationWorkerPool) {
    // Always initialize direct compiler as fallback
    this.directCompiler = new ArduinoCompiler();
    
    // Try to use worker pool in production if available
    this.usePool = process.env.NODE_ENV === "production";
    
    if (this.usePool && pool) {
      this.pool = pool;
    I} else if (this.usePool) {
      try {
        this.pool = getCompilationPool();
      } catch {
        // Worker pool unavailable (e.g., worker files not found) - fall back to direct compiler
        // This is expected in development mode and is handled gracefully
        this.pool = null;
      }
    } else {
      // Development mode: use direct compiler (worker threads don't work with tsx/@shared/*)
      this.pool = null;
    }
  }
 
  /**
   * Compile code through the worker pool (production) or directly (development)
   * 
   * Signature matches ArduinoCompiler.compile() for drop-in compatibility
   */
  async compile(
    code: string,
    headers?: Array<{ name: string; content: string }>,
    tempRoot?: string,
    options?: CompileRequestOptions,
  ): Promise<CompilationResult> {
    if (this.usePool && this.pool) {
      try {
        const task: CompileRequestPayload = { code, headers, tempRoot, ...options };
        return await this.pool.compile(task);
      } catch {
        // Pool failed to compile (e.g., workers not operational) - fall back to direct compiler
        // This is an expected fallback path when workers are unavailable
        if (!this.directCompiler) {
          throw new Error("Neither pool nor direct compiler available");
        }
        return await this.directCompiler.compile(code, headers, tempRoot, options);
      }
    } else {
      // Fall back to direct compiler (always available)
      if (!this.directCompiler) {
        throw new Error("Neither pool nor direct compiler available");
      }
      return await this.directCompiler.compile(code, headers, tempRoot, options);
    }
  }
 
  /**
   * Check if worker pool is operational
   */
  isOperational(): boolean {
    return this.usePool && this.pool !== null;
  }
 
  /**
   * Get current pool statistics (production only)
   */
  getStats() {
    if (this.pool) {
      return this.pool.getStats();
    }
    return {
      activeWorkers: 0,
      totalTasks: 0,
      completedTasks: 0,
      failedTasks: 0,
      avgCompileTimeMs: 0,
      queuedTasks: 0,
    };
  }
 
  /**
   * Gracefully shutdown the pool (production only)
   */
  async shutdown(): Promise<void> {
    if (this.pool) {
      await this.pool.shutdown();
    }
  }
}
 
/**
 * Singleton instance for application-wide use
 */
let pooledCompilerInstance: PooledCompiler | null = null;
 
export function getPooledCompiler(): PooledCompiler {
  pooledCompilerInstance ??= new PooledCompiler();
  return pooledCompilerInstance;
}
 
// setPooledCompiler removed; not needed