I'm writing a Nodejs based service, N, that sits between entities A and B.
A <----> N <----> B
App A POST
s a synchronous request to N, which N must respond to with data it can only get by calling an external service B.
The problem is, B is an asynchronous service/API: Anything N POST
s to B is responded to first with an HTTP 202 ("request accepted"), and then later with the actual data as a callback POST
request from B to N. So, essentially, inside the single-threaded N, I have to somehow keep the current, synchronous request from A "on hold" without blocking other potential requests from A to N while the asynchronous message exchange between N and B completes to service the request from A currently on hold.
Is this possible in Nodejs, say, using promises or async
/await
magic?
CodePudding user response:
With request id, local cache & timeout, you could do something like this:
const requestIdAndResponseDetailsMap = {};
router.post('/request-from-a', function requestFromAHandler(request, response) {
const requestId = request.body.id;
makeCallToB(request.body); // ensure that request id is passed to B and sent in the call from B to N.
cacheServiceAResponseWithTimeout(requestId, response);
});
router.post('/callback-from-b', function callbackFromBHandler(request, response) {
const dataFromB = request.body;
tryRespondToA(dataFromB);
response.json({ success: true });
});
function tryRespondToA(responseFromB) {
const requestId = responseFromB.id;
const cachedData = requestIdAndResponseDetailsMap[requestId];
if(cachedData === undefined) {
return;
}
delete requestIdAndResponseDetailsMap[requestId];
clearTimeout(cachedData.timerReference);
cachedData.response.json(responseFromB);
}
function cacheServiceAResponseWithTimeout(requestId, response) {
const timerReference = setTimeout(function timerCallback() {
const cachedData = requestIdAndResponseDetailsMap[requestId];
delete requestIdAndResponseDetailsMap[requestId];
cachedData.response.json({ message: 'Service B request timed out' });
}, TIMEOUT_IN_MILLISECONDS);
requestIdAndResponseDetailsMap[requestId] = { response, timerReference };
}