Skip to content

Instantly share code, notes, and snippets.

@dlukes
Created January 20, 2017 09:29
Show Gist options
  • Save dlukes/54f091daff585b085ce597dae6bd1958 to your computer and use it in GitHub Desktop.
Save dlukes/54f091daff585b085ce597dae6bd1958 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}.`);
});
@guyeatspants
Copy link

Very cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment