summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2020-06-18 22:15:29 +0200
committerTom Smeding <tom.smeding@gmail.com>2020-06-18 22:15:29 +0200
commitfd90538fcc63fa55be516fa29c53ca82c5c98a23 (patch)
tree4848d179062f59a689d38b72616c7998d6a9b124
parente66f29ff85392e3c06e9033e37ead06a9d9d5daa (diff)
blog: Fix rendering race condition with multiple clients
-rw-r--r--modules/blog/blog.js43
1 files changed, 38 insertions, 5 deletions
diff --git a/modules/blog/blog.js b/modules/blog/blog.js
index 0b7785b..b6085d9 100644
--- a/modules/blog/blog.js
+++ b/modules/blog/blog.js
@@ -9,7 +9,23 @@ let moddir = null;
let repodir = null;
const repoRemote = "https://git.tomsmeding.com/blog";
+// Cache for rendered posts; null if currently being rendered
let templateCache = new Map();
+// Clients that requested a post that is currently being rendered; values are
+// callbacks that take (http status code, rendered html [= null if status != 200])
+let renderWatchers = new Map();
+
+function triggerRenderWatchers(path, statusCode, rendered) {
+ const list = renderWatchers.get(path);
+ if (list !== undefined) {
+ try {
+ for (const callback of list) callback(statusCode, rendered);
+ } catch(e) {
+ console.error("While triggering render watchers:", e);
+ }
+ renderWatchers.delete(path);
+ }
+}
function fetch(url) {
return new Promise((resolve, reject) => {
@@ -111,21 +127,38 @@ module.exports = (app, io, _moddir) => {
return;
}
- const path = req.path.slice(6).replace(/\.html$/, "");
-
- if (templateCache.has(path)) {
- res.send(templateCache.get(path));
+ const path = req.path
+ .slice(6)
+ .replace(/\/[\/]*/g, "/")
+ .replace(/\.html$/, "");
+
+ const fromCache = templateCache.get(path);
+
+ if (fromCache != null) { // neither null nor undefined
+ res.send(fromCache);
+ } else if (fromCache !== undefined) {
+ // Is currently being renderered for another client
+ if (!renderWatchers.has(path)) renderWatchers.set(path, []);
+ renderWatchers.get(path).push((statusCode, rendered) => {
+ if (statusCode == 200) res.send(rendered);
+ else res.sendStatus(statusCode);
+ });
} else {
+ // Indicate that this path is currently being rendered
+ templateCache.set(path, null);
+
generateTemplate(repodir, path ? path + ".html" : undefined)
.then(rendered => {
- // TODO: fix rendering race condition
templateCache.set(path, rendered);
+ triggerRenderWatchers(path, 200, rendered);
res.send(rendered);
})
.catch(err => {
if (err.code && err.code == "ENOENT") {
+ triggerRenderWatchers(path, 400, null);
res.sendStatus(404);
} else {
+ triggerRenderWatchers(path, 500, null);
console.error(err);
res.sendStatus(500);
}