diff --git a/deno_server.ts b/deno_server.ts index c9c1e2c..d1907a9 100644 --- a/deno_server.ts +++ b/deno_server.ts @@ -6,33 +6,56 @@ const States = Object.freeze({ TIMEOUT: "TIMEOUT", }); +// Create a pool of workers. +const workerPool: { worker: Worker; inUse: boolean }[] = []; +const numWorkers = navigator.hardwareConcurrency; + +for (let i = 0; i < numWorkers; i++) { + const worker = new Worker(new URL("./worker.ts", import.meta.url).href, { + type: "module", + deno: { + namespace: true, + permissions: "inherit", + }, + }); + workerPool.push({ worker, inUse: false }); +} + +function getAvailableWorker() { + return new Promise((resolve) => { + const check = () => { + const availableWorker = workerPool.find((w) => !w.inUse); + if (availableWorker) { + availableWorker.inUse = true; + resolve(availableWorker); + } else { + setTimeout(check, 100); // Check again in 100ms. + } + }; + check(); + }); +} + async function handler(req: Request): Promise { if (req.method !== "POST" || new URL(req.url).pathname !== "/execute") { return new Response("Not Found", { status: 404 }); } + const availableWorker = (await getAvailableWorker()) as { + worker: Worker; + inUse: boolean; + }; + try { const body = await req.json(); const { code = "", request = {}, environment = {}, name } = body; - const worker = new Worker(new URL("./worker.ts", import.meta.url).href, { - type: "module", - // The `deno` option is now stable, but your editor might show a TS error - // if it's not configured for Deno. This will run correctly with Deno. - deno: { - namespace: true, // recommended for workers - permissions: "inherit", - }, - }); - const executionPromise = new Promise((resolve, reject) => { - worker.onmessage = (e) => { + availableWorker.worker.onmessage = (e) => { resolve(e.data); - worker.terminate(); }; - worker.onerror = (e) => { + availableWorker.worker.onerror = (e) => { reject(new Error(`Worker error: ${e.message}`)); - worker.terminate(); }; }); @@ -40,7 +63,7 @@ async function handler(req: Request): Promise { setTimeout(() => reject(new Error("Timeout")), TIMEOUT_MS) ); - worker.postMessage({ code, request, environment, name }); + availableWorker.worker.postMessage({ code, request, environment, name }); const startTime = performance.now(); try { @@ -49,7 +72,6 @@ async function handler(req: Request): Promise { headers: { "Content-Type": "application/json" }, }); } catch (err) { - worker.terminate(); const executionTime = performance.now() - startTime; const payload = { status: States.TIMEOUT, @@ -65,9 +87,11 @@ async function handler(req: Request): Promise { } } catch (e) { return new Response(`Bad Request: ${e.message}`, { status: 400 }); + } finally { + availableWorker.inUse = false; // Release the worker. } } -console.log("⚡ Deno server ready on :8000"); +console.log(`⚡ Deno server ready on :8000 with ${numWorkers} workers.`); await serve(handler, { port: 8000 });