\n
Results:
\n\n","author":{"@type":"Person","name":"adska"},"upvoteCount":1,"answerCount":2,"acceptedAnswer":{"@type":"Answer","text":"To guarantee that the result is not calculated multiple times for concurrent requests, you need to implement some kind of locking mechanism (as you expected).
\nHere's a very basic example of what your code could look like, that simply pushes requests to a queue if the mutex is currently locked. If not the result gets calculated and for all pending requests a response with the calculated value will be sent:
\nconst express = require('express');\nconst app = express();\n\nclass Mutex {\n constructor() {\n this.queue = [];\n this.locked = false;\n }\n\n lock() {\n return new Promise((resolve, reject) => {\n if (this.locked) {\n this.queue.push([resolve, reject]);\n } else {\n this.locked = true;\n resolve();\n }\n });\n }\n\n release(value) {\n if (this.queue.length > 0) {\n const [resolve, reject] = this.queue.shift();\n resolve(value);\n } else {\n this.locked = false;\n }\n }\n}\n\nconst getResultsMutex = new Mutex();\n\nfunction getResults() {\n return new Promise((resolve => {\n setTimeout(() => resolve(Math.random()), 5000);\n }))\n}\n\nfunction sendResponse(result, req, res) {\n res.send("The result is " + result);\n}\n\napp.get('/getresults', async (req, res) => {\n let result = await getResultsMutex.lock();\n if (!result) {\n result = await getResults();\n }\n sendResponse(result, req, res);\n getResultsMutex.release(result);\n});\n\napp.listen(4000, function () {\n console.log("Server is running at port 4000");\n});\n
\n","author":{"@type":"Person","name":"eol"},"upvoteCount":1}}}Reputation: 47
Multiple users can call requests at the same time, so I want to do if one user calls to request and calculation of results is being started then when another user calls the same request results calculation is not being started, but wait for results which were asked for the first user. In other words, the calculation of the result should be started only if it is not 'locked' by another user, if it is - then waits for the result.
Edited
Results:
Upvotes: 1
Views: 2062
Reputation: 24565
To guarantee that the result is not calculated multiple times for concurrent requests, you need to implement some kind of locking mechanism (as you expected).
Here's a very basic example of what your code could look like, that simply pushes requests to a queue if the mutex is currently locked. If not the result gets calculated and for all pending requests a response with the calculated value will be sent:
const express = require('express');
const app = express();
class Mutex {
constructor() {
this.queue = [];
this.locked = false;
}
lock() {
return new Promise((resolve, reject) => {
if (this.locked) {
this.queue.push([resolve, reject]);
} else {
this.locked = true;
resolve();
}
});
}
release(value) {
if (this.queue.length > 0) {
const [resolve, reject] = this.queue.shift();
resolve(value);
} else {
this.locked = false;
}
}
}
const getResultsMutex = new Mutex();
function getResults() {
return new Promise((resolve => {
setTimeout(() => resolve(Math.random()), 5000);
}))
}
function sendResponse(result, req, res) {
res.send("The result is " + result);
}
app.get('/getresults', async (req, res) => {
let result = await getResultsMutex.lock();
if (!result) {
result = await getResults();
}
sendResponse(result, req, res);
getResultsMutex.release(result);
});
app.listen(4000, function () {
console.log("Server is running at port 4000");
});
Upvotes: 1
Reputation: 195
Like this?
/** @type {[express.Request, express.Response][]} */
let requestQueue = [];
/**
* @param {express.Request} req
* @param {express.Response} res
*/
async function processRequest( req, res ) {
var result = await GetResults();
res.end(result);
if (requestQueue.length !== 0) processRequest.apply(requestQueue.shift());
}
app.get("/getresults", (req, res) => {
if (requestQueue.length !== 0) return requestQueue.push([req, res]);
processRequest(req, res);
});
EDIT: If they should all receive the same result, then this code:
/** @type {Promise} */
let requestPromise = null;
app.get("/getresults", (req, res) => {
if (requestPromise === null) requestPromise = GetResults().finally(() => requestPromise = null); // returns a promise
res.send(await requestPromise);
});
Upvotes: 0