I am using meteor. I have a route defined in iron router as follows,
Router.route('/api/generatereceipt', {where: 'server'}).post(function(req, res, next) {
console.log("API: generatereceipt invoked.");
const reqBody = req.body;
....
}
I want to generate a receipt one at a time. i.e. the receipt needs to have a unique number which is incremental in nature.
Right now I'm reading the previously stored receipt number and incrementing it by one. I consider that as the receipt number for currently processing receipt.
However, This works fine as long as the generatereceipt
API is not called concurrently by multiple clients. When the API is called simultaneously, the same receipt number is considered for all the concurrently processed receipts.
Therefore I want to make a request check if the same REST API is called by some other client in some other request is under process. If it is in the process then I want to wait till its execution in that request thread finishes.
There should be no issue with concurrent requests. See the following example:
import { Meteor } from 'meteor/meteor'
import { WebApp } from 'meteor/webapp'
import { HTTP } from 'meteor/http'
// create a simple HTTP route
WebApp.connectHandlers.use('/api/generatereceipt', function (req, res, next) {
// random 0 - 50ms timeout to simulate response delay
const randomTimeout = Math.floor(Math.random() * 50)
// use Meteor's Promise.await to await async in non-async functions
// --> should prevent troubles with legacy iron-router
const receipt = Promise.await(getReceipt())
setTimeout(() => {
res.writeHead(200)
res.end(String(receipt))
}, randomTimeout)
})
// increment id and return new value
let receiptId = 0
async function getReceipt () {
return receiptId++
}
Meteor.startup(function () {
let testCount = 0
const url = Meteor.absoluteUrl('/api/generatereceipt')
// simulate concurrent calls by using a timeout of 0
function call (id) {
setTimeout(Meteor.bindEnvironment(() => {
// simulate calling the /api/generatereceipt route
const response = HTTP.get(url)
console.log(id, ' => ', response.content) // should match
}, 0))
}
for (let i = 0; i < 25; i++) {
call(testCount++)
}
})
as you can see, the calls will resolve to the incremented ids:
=> Meteor server restarted
I20200703-09:59:15.911(2)? 9 => 9
I20200703-09:59:15.912(2)? 7 => 7
I20200703-09:59:15.913(2)? 4 => 4
I20200703-09:59:15.913(2)? 0 => 0
I20200703-09:59:15.913(2)? 21 => 21
I20200703-09:59:15.913(2)? 24 => 24
I20200703-09:59:15.913(2)? 17 => 17
I20200703-09:59:15.913(2)? 18 => 18
I20200703-09:59:15.915(2)? 2 => 2
I20200703-09:59:15.917(2)? 19 => 19
I20200703-09:59:15.923(2)? 6 => 6
I20200703-09:59:15.923(2)? 23 => 23
I20200703-09:59:15.925(2)? 11 => 11
I20200703-09:59:15.928(2)? 8 => 8
I20200703-09:59:15.931(2)? 16 => 16
I20200703-09:59:15.932(2)? 10 => 10
I20200703-09:59:15.934(2)? 5 => 5
I20200703-09:59:15.934(2)? 13 => 13
I20200703-09:59:15.934(2)? 22 => 22
I20200703-09:59:15.936(2)? 20 => 20
I20200703-09:59:15.936(2)? 15 => 15
I20200703-09:59:15.939(2)? 14 => 14
I20200703-09:59:15.940(2)? 1 => 1
I20200703-09:59:15.940(2)? 3 => 3
I20200703-09:59:15.943(2)? 12 => 12