将 NodeJS 应用程序中的订单请求延迟一段时间
Delay order requests in NodeJS Application for some specific duration
我正在为我的一个客户开发一个订购应用程序,他们想为他们的客户实现一种点击和收集功能。因此,客户通常从我们的应用程序中选择商品并下订单,然后我们处理付款和相关事宜并将其发送到第三方 POS,剩下的由他们完成。客户希望让客户能够灵活地在他们选择的时间收集物品。客户发送一个请求,我们将其保留一段时间(默认为一小时),并在一小时后将其发送到 POS。我刚刚用 setTimeout 取消了请求,它似乎工作正常,但如果服务器运行一段时间,可能还有其他我不知道的含义。那么,我的问题的最佳解决方案是什么?
您是在谈论在给定的等待时间(比如一小时)后交付订购商品的请求,对吧?对我来说,这听起来像是一项合同义务,必须安全地存储在您客户的系统中,而不能简单地保存在 Javascript 应用程序的内存中。正如你所说,这个应用程序可能会崩溃并重新启动,但合同义务仍然存在。
您的订购应用程序应将计算出的送货时间(例如从现在起一小时)的送货请求写入数据库,例如
{
"OrderNumber": ...,
"POS": ...,
"DeliveryTime": "2022-04-02T12:00:00+02:00",
"Status": "AwaitingDelivery"
}
那么您应该有一个进程重复扫描此数据库以查找状态为 AwaitingDelivery
且 DeliveryTime
已通过且
的条目
- 根据他们的
OrderNumber
使用订单信息丰富他们(假设您有另一个包含订单的数据库 table)
- 将丰富的数据发送到给定的
POS
- 将他们的状态从
AwaitingDelivery
更改为 HandoverToPOS
- 当 POS 的响应进来时,将状态从
HandoverToPOS
更改为 Completed
。
虽然步骤 1 到 3 可以同步执行,但在步骤 4 中等待响应会引入异步性。你可以在 Node.js 中这样写
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
请注意,这再次依赖于 Javascript 应用程序的内存:如果应用程序在第 3 步后重启,则永远不会执行第 4 步并且条目保持状态 HandoverToPOS
。但如果 POS 使用 200 以外的 HTTP 代码进行响应,条目也会保持此状态。
拥有额外状态 HandoverToPOS
的好处是您(或者更确切地说,您的客户)可以跟进此类条目。为了与 POS 建立顺畅的业务关系,并为了客户的利益,这也应该自动化,例如,通过另一个进程重复扫描数据库以查找状态 HandoverToPOS
中的条目并将它们发送到 POS再次,这次有一些迹象表明这是一个重复请求。此指示可防止 POS 仅因为对第一个 https://url-of-pos/delivery
请求的响应丢失而向同一客户发送两台洗衣机。
(请注意,上面的代码片段发送第一个带有 "Status": "AwaitingDelivery"
的 https://url-of-pos/delivery
请求,然后 然后 在数据库上将其更改为 "Status": "HandoverToPOS"
, 因此第二个 https://url-of-pos/delivery
请求的状态将与第一个不同。这可以向 POS 指示这是一个重复请求。但是入站服务 https://url-of-pos/delivery
必须能够理解当然是这条信息。)
附录:
“重复扫描”过程可以在 Node.js 中实现为 re-invokes 本身在末尾使用 setTimeout
的函数。
async function scanDeliveries() {
var entries = await db.query("select * from ...");
for (var entry of entries) {
await theCodeAbove(entry);
}
setTimeout(scanDeliveries, 60000);
}
成功扫描交付后(这可能需要一些时间,因为它本质上是异步的),该函数将在 60 秒后 re-invoke 自身。在这 60 秒内以及扫描的异步部分,您的其余代码将能够处理更多传入的客户订单。
没有数据保存在内存中,因此如果重新启动整个应用程序也不会造成伤害。
我正在为我的一个客户开发一个订购应用程序,他们想为他们的客户实现一种点击和收集功能。因此,客户通常从我们的应用程序中选择商品并下订单,然后我们处理付款和相关事宜并将其发送到第三方 POS,剩下的由他们完成。客户希望让客户能够灵活地在他们选择的时间收集物品。客户发送一个请求,我们将其保留一段时间(默认为一小时),并在一小时后将其发送到 POS。我刚刚用 setTimeout 取消了请求,它似乎工作正常,但如果服务器运行一段时间,可能还有其他我不知道的含义。那么,我的问题的最佳解决方案是什么?
您是在谈论在给定的等待时间(比如一小时)后交付订购商品的请求,对吧?对我来说,这听起来像是一项合同义务,必须安全地存储在您客户的系统中,而不能简单地保存在 Javascript 应用程序的内存中。正如你所说,这个应用程序可能会崩溃并重新启动,但合同义务仍然存在。
您的订购应用程序应将计算出的送货时间(例如从现在起一小时)的送货请求写入数据库,例如
{
"OrderNumber": ...,
"POS": ...,
"DeliveryTime": "2022-04-02T12:00:00+02:00",
"Status": "AwaitingDelivery"
}
那么您应该有一个进程重复扫描此数据库以查找状态为 AwaitingDelivery
且 DeliveryTime
已通过且
- 根据他们的
OrderNumber
使用订单信息丰富他们(假设您有另一个包含订单的数据库 table) - 将丰富的数据发送到给定的
POS
- 将他们的状态从
AwaitingDelivery
更改为HandoverToPOS
- 当 POS 的响应进来时,将状态从
HandoverToPOS
更改为Completed
。
虽然步骤 1 到 3 可以同步执行,但在步骤 4 中等待响应会引入异步性。你可以在 Node.js 中这样写
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
请注意,这再次依赖于 Javascript 应用程序的内存:如果应用程序在第 3 步后重启,则永远不会执行第 4 步并且条目保持状态 HandoverToPOS
。但如果 POS 使用 200 以外的 HTTP 代码进行响应,条目也会保持此状态。
拥有额外状态 HandoverToPOS
的好处是您(或者更确切地说,您的客户)可以跟进此类条目。为了与 POS 建立顺畅的业务关系,并为了客户的利益,这也应该自动化,例如,通过另一个进程重复扫描数据库以查找状态 HandoverToPOS
中的条目并将它们发送到 POS再次,这次有一些迹象表明这是一个重复请求。此指示可防止 POS 仅因为对第一个 https://url-of-pos/delivery
请求的响应丢失而向同一客户发送两台洗衣机。
(请注意,上面的代码片段发送第一个带有 "Status": "AwaitingDelivery"
的 https://url-of-pos/delivery
请求,然后 然后 在数据库上将其更改为 "Status": "HandoverToPOS"
, 因此第二个 https://url-of-pos/delivery
请求的状态将与第一个不同。这可以向 POS 指示这是一个重复请求。但是入站服务 https://url-of-pos/delivery
必须能够理解当然是这条信息。)
附录:
“重复扫描”过程可以在 Node.js 中实现为 re-invokes 本身在末尾使用 setTimeout
的函数。
async function scanDeliveries() {
var entries = await db.query("select * from ...");
for (var entry of entries) {
await theCodeAbove(entry);
}
setTimeout(scanDeliveries, 60000);
}
成功扫描交付后(这可能需要一些时间,因为它本质上是异步的),该函数将在 60 秒后 re-invoke 自身。在这 60 秒内以及扫描的异步部分,您的其余代码将能够处理更多传入的客户订单。
没有数据保存在内存中,因此如果重新启动整个应用程序也不会造成伤害。