Skip to content

Instantly share code, notes, and snippets.

@MinSomai
Forked from dlukes/server.js
Created September 19, 2022 03:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MinSomai/fc5698eba4647fcccc6b8a6cf6ed8a4c to your computer and use it in GitHub Desktop.
Save MinSomai/fc5698eba4647fcccc6b8a6cf6ed8a4c to your computer and use it in GitHub Desktop.
Pattern for using Promise-based background jobs in Node + Express.
/* A quick reminder on how to use Promises with Node and Express in order to run potentially
* time-consuming jobs asynchronously (assuming the jobs are able to run in the background thanks to
* libuv and actually return Promises).
*
* Start the server, navigate to /startjob, then refresh a few times, the job should be in progress.
* You can navigate elsewhere in the "app" in other browser tabs in the meanwhile (/). After about
* 20s, you should get a result by refreshing the tab where you originally submitted the job.
*
* I hope this pattern will be useful e.g. for processing images with the `sharp` library (see
* <http://sharp.dimens.io>).
*/
const express = require("/usr/lib/node_modules/express");
const app = express();
const PORT = process.env.PORT || 3000;
// this is where we'll store the results of our jobs by uuid once they're done
const JOBS = {};
app.get("/", (req, res) => {
res.send("It works!");
});
app.get("/startjob", (req, res) => {
let times = [100, 1000, 10000, 20000];
let promises = [];
for (let time of times) {
promises.push(new Promise((resolve, reject) => {
setTimeout(resolve, time, `${time} is done.`);
}));
}
// obviously, you'd want to generate a real uuid here to avoid collisions
let uuid = "uuid";
Promise.all(promises).then(values => { JOBS[uuid] = values; });
res.redirect(`progress/${uuid}`);
});
app.get("/progress/:uuid", (req, res) => {
if (JOBS[req.params.uuid] === undefined) {
res.send("Still processing your request.");
} else {
res.send(`Here's your result: ${JOBS[req.params.uuid]}.`);
// instead of immediately deleting the result of the job (and making it impossible for the user
// to fetch it a second time if they e.g. accidentally cancel the download), it would be better
// to run a periodic cleanup task on `JOBS`
delete JOBS[req.params.uuid];
}
});
app.listen(PORT, () => {
console.log(`Listening on localhost:${PORT}.`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment