How can I manage lengthy task functions in Node.js Express.js to manage lengthy task functions effectively, and prevent timeout errors? Presently, my application contains a time-consuming function, the response of which I don’t require immediately, but I still want it to execute its tasks. How can I ensure that I receive the API response while allowing the function to execute in the background?
Why i tried: (I’m using typescript)
import fs from 'fs'
import { v4 as uuidv4 } from 'uuid';
import { Worker } from 'node:worker_threads';
api.ts
router.post('/run-long-task', async (req, res) => {
const taskId = uuidv4();
const worker = new Worker(file, {
workerData: { taskId },
eval: true
});
tasksById.set(taskId, {
status: 'running',
started: Date.now(),
});
worker.on('message', async () => {
try {
tasksById.set(taskId, { status: 'completed' });
} catch (error) {
tasksById.set(taskId, { status: 'error', error: error.message });
}
});
tasksById.set(taskId, {
status: "running",
started: Date.now(),
worker,
});
worker.on("message", (status) => {
tasksById.set(taskId, { status });
});
worker.on("error", (error) => {
tasksById.set(taskId, { status: "error", error: error.message });
});
worker.on("exit", (code) => {
if (code !== 0) {
if (tasksById.get(taskId)?.status === "running") {
tasksById.set(taskId, {
status: "error",
error: `Worker stopped with exit code ${code}`,
});
} else {
}
}
});
res.json({ taskId });
})
worker.ts:
import { parentPort } from "node:worker_threads";
async function performTask() {
// Long Task Function
}
if (parentPort) {
parentPort.on('message', (task) => {
performTask()
parentPort?.postMessage({ success: '1' });
});
}
2
Answers
If the task takes so long that your browser times out the request while it’s running, you don’t want to run it on the main thread at all, whether before or after you send your response to that API call — because the main thread will be tied up and unable to process any subsequent calls until it’s finished.
Instead, run the task in a worker thread. Worker threads run independently of the main thread. You can use messaging to communicate between the main thread and the worker thread (for instance, so the worker knows what to start doing, and later the main thread knows the task is complete).
Here’s a very rough example, see comments:
Again, that’s very rough.
That’s just one approach, though. Another approach would be to start the worker on startup but have it sit there idle, then use messaging to tell it to process something.
With example of T.J. Crowder and this example try tu put your long function inside worker.ts parentPort.on().
index.ts:
worker.ts: