I am working in an ordering application for one of my client and they want to implement kind of click and collect functionality for their customer. So, the customer normally selects item from our app and place an order then, we handle payment and stuffs and send it to some third party POS and they do the rest. The client wants to give a customer flexibility to collect item at the time of their choice. Client sends a request we hold it for some specific time(default is one hour) and send it to POS after one hour. I have Just dealayed the request with setTimeout and it seem to be working fine but if server goes for sometime and there might be other implication which i am not aware of. So, what will be the best solution for my problem??
CodePudding user response:
You are talking about a request to deliver the ordered items after a given waiting period (one hour, say), right? To me this sounds like a contractual obligation which must be safely stored in your client's system and cannot simply be kept in the memory of a Javascript application. As you say, this application might break down and be restarted, but then the contractual obligation must still be there.
Your ordering application should write the delivery request with the computed delivery time (one hour from now, say) to a database, something like
{
"OrderNumber": ...,
"POS": ...,
"DeliveryTime": "2022-04-02T12:00:00 02:00",
"Status": "AwaitingDelivery"
}
Then you should have a process that repeatedly scans this database for entries in status AwaitingDelivery
whose DeliveryTime
has passed and
- enrich them with order information according to their
OrderNumber
(assuming you have another database table that contains the orders) - send the enriched data to the given
POS
- change their status from
AwaitingDelivery
toHandoverToPOS
- when the response from the POS comes in, change the status from
HandoverToPOS
toCompleted
.
While steps 1 thru 3 can be carried out synchronously, waiting for the response in step 4 introduces asynchronousness. You could write this in Node.js like
var entry = readFromDatabase(...);
enrichWithOrderData(entry); // step 1
https.request("https://url-of-pos/delivery", {method: "POST", ...})
.on("response", function(r) {
if (r.statusCode === 200) {
entry.status = "Completed";
writeToDatabase(entry); // step 4
}
})
.end(JSON.stringify(entry)); // step 2
entry.status = "HandoverToPOS";
writeToDatabase(entry); // step 3
Note that this again relies on the memory of the Javascript application: If the application suffers a restart after step 3, step 4 is never carried out and the entry remains in status HandoverToPOS
. But entries also remain in this status if the POS responds with an HTTP code other than 200.
The advantage of having the extra status HandoverToPOS
is that you (or rather, your client) can follow up on such entries. For a smooth business relationship with the POS, and for the benefit of the customers, this should be automated as well, for example, by another process that repeatedly scans the database for entries in status HandoverToPOS
and sends them to the POS again, this time with some indication that this is a repeat request. This indication prevents that the POS sends two washing machines to the same customer just because the response to the first https://url-of-pos/delivery
request got lost.
(Note that the code snippet above sends the first https://url-of-pos/delivery
request with "Status": "AwaitingDelivery"
and then changes it to "Status": "HandoverToPOS"
on the database, so that a second https://url-of-pos/delivery
request would have a different status than the first. This can serve as an indication to the POS that this is a repeat request. But the inbound service https://url-of-pos/delivery
must be able to understand this piece of information, of course.)
Addendum:
The "repeated scan" process can be implemented in Node.js as a function that re-invokes itself using setTimeout
at the end.
async function scanDeliveries() {
var entries = await db.query("select * from ...");
for (var entry of entries) {
await theCodeAbove(entry);
}
setTimeout(scanDeliveries, 60000);
}
After a successful scan of the deliveries (which may take some time, because it is asynchronous in nature), the function will re-invoke itself after 60 seconds. During these 60 seconds, and during the asynchronous parts of the scan, the rest of your code will be able to handle more incoming customer orders.
No data is kept in memory, therefore it does not hurt if the whole application is restarted.