Home > Net >  Delay order requests in NodeJS Application for some specific duration
Delay order requests in NodeJS Application for some specific duration

Time:04-03

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

  1. enrich them with order information according to their OrderNumber (assuming you have another database table that contains the orders)
  2. send the enriched data to the given POS
  3. change their status from AwaitingDelivery to HandoverToPOS
  4. when the response from the POS comes in, change the status from HandoverToPOS to Completed.

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.

  • Related