Created
January 20, 2017 09:29
-
-
Save dlukes/54f091daff585b085ce597dae6bd1958 to your computer and use it in GitHub Desktop.
Pattern for using Promise-based background jobs in Node + Express.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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
Very cool!