Enqueue dev server response work when thread pool is all busy.

This commit is contained in:
Dillon Kearns 2021-07-20 14:14:56 -07:00
parent 4ede380fab
commit 951d57a12a

View File

@ -17,6 +17,7 @@ const baseMiddleware = require("./basepath-middleware.js");
* @param {{ port: string; base: string }} options
*/
async function start(options) {
let threadReadyQueue = [];
let pool = [];
ensureDirSync(path.join(process.cwd(), ".elm-pages", "http-response-cache"));
const cpuCount = os.cpus().length;
@ -65,6 +66,7 @@ async function start(options) {
for (let index = 0; index < poolSize; index++) {
pool.push(initWorker(options.base));
}
runPendingWork();
}
setup();
@ -115,7 +117,7 @@ async function start(options) {
if (request.url && request.url.startsWith("/stream")) {
handleStream(request, response);
} else {
handleNavigationRequest(request, response, next);
await handleNavigationRequest(request, response, next);
}
}
@ -226,16 +228,20 @@ async function start(options) {
);
}
/**
* @param {string} pathname
* @param {((value: any) => any) | null | undefined} onOk
* @param {((reason: any) => PromiseLike<never>) | null | undefined} onErr
*/
function runRenderThread(pathname, onOk, onErr) {
const readyThread = pool.find((thread) => thread.ready);
if (!readyThread) {
readyThread = pool[0];
}
const cleanUpThread = () => {
let cleanUpThread = () => {};
return new Promise(async (resolve, reject) => {
const readyThread = await waitForThread();
console.log(`Rendering ${pathname}`, readyThread.worker.threadId);
cleanUpThread = () => {
cleanUp(readyThread);
};
return new Promise((resolve, reject) => {
if (readyThread) {
readyThread.ready = false;
readyThread.worker.postMessage({
mode: "dev-server",
@ -256,9 +262,6 @@ async function start(options) {
readyThread.worker.on("error", (error) => {
reject(error.context);
});
} else {
console.error("TODO - running out of ready threads not yet handled");
}
})
.then(onOk)
.catch(onErr)
@ -271,6 +274,7 @@ async function start(options) {
thread.worker.removeAllListeners("message");
thread.worker.removeAllListeners("error");
thread.ready = true;
runPendingWork();
}
/**
@ -283,7 +287,7 @@ async function start(options) {
const pathname = urlParts.pathname || "";
try {
await pendingCliCompile;
runRenderThread(
await runRenderThread(
pathname,
function (renderResult) {
const is404 = renderResult.is404;
@ -357,7 +361,27 @@ async function start(options) {
next();
}
}
/**
* @returns {Promise<{ ready:boolean; worker: Worker }>}
* */
function waitForThread() {
return new Promise((resolve, reject) => {
threadReadyQueue.push(resolve);
runPendingWork();
});
}
function runPendingWork() {
const readyThreads = pool.filter((thread) => thread.ready);
readyThreads.forEach((readyThread) => {
const startTask = threadReadyQueue.shift();
if (startTask) {
startTask(readyThread);
}
});
}
/**
* @param {string} basePath
*/
@ -374,6 +398,7 @@ function initWorker(basePath) {
});
return newWorker;
}
}
function timeMiddleware() {
return (req, res, next) => {