Apr*_*nig 1 node.js express sequelize.js
我从 webhook 收到 n 个 post 请求(在每个 webhook 触发器上)。来自同一触发器的所有请求的数据都是相同的 - 它们都具有相同的“orderId”。我只想保存其中一个请求,因此在每个端点命中时,我都会检查此特定 orderId 是否作为数据库中的一行存在,否则 - 创建它。
if (await orderIdExists === null) {
await Order.create(
{
userId,
status: PENDING,
price,
...
}
);
await sleep(3000)
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
}
return res.status(HttpStatus.OK).send({success: true})
} catch (error) {
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({success: false})
}
}
else {
return res.status(HttpStatus.UNAUTHORIZED).send(responseBuilder(false, responseErrorCodes.INVALID_API_KEY, {}, req.t));
}
}
Run Code Online (Sandbox Code Playgroud)
问题是在 Sequelize 设法将新创建的订单保存在数据库中之前(所有 n 个 post 请求在 1 秒或更短的时间内到达 enpoint),我已经从其他 n 个 post 请求中获得了另一个端点命中,而 orderIdExists 仍然等于null,所以它最终会创建更多相同的订单。一种(不太好的解决方案)是使 orderId 在数据库中唯一,这会阻止创建具有相同 orderId 的 on order,但无论如何都会尝试这样做,这会导致数据库中的空 id 增量。任何想法将不胜感激。PS如你所见,我尝试添加“睡眠”功能但无济于事。
您的数据库无法在下一个请求到达之前完成其保存操作。该问题类似于“狗堆效应”或“缓存猛击”。
这需要更多地思考如何构建问题:换句话说,“解决方案”将更具哲学性,并且可能与代码关系不大,因此您在 StackOverflow 上的结果可能会有所不同。
“睡眠”解决方案根本不是解决方案:无法保证数据库操作可能需要多长时间,或者在另一个重复请求到达之前您可能需要等待多长时间。根据经验,任何时候将“睡眠”部署为并发问题的“解决方案”,通常都是错误的选择。
让我提出两种可能的处理方法:
选项 1:只写:即在写入数据库之前不要尝试通过读取数据库来“解决”此问题。只要保持通往数据库的管道尽可能愚蠢并继续写入即可。例如,考虑一个“日志记录”表,它只存储 webhook 向其抛出的任何内容 - 不要尝试从中读取,只需继续插入(或更新插入)。如果您收到有关特定订单的 100 个 ping-backs,那就这样吧:您的表将记录所有内容,如果您最终得到单个 100 行orderId,那么让其他下游进程担心如何处理所有这些重复数据。据推测,Sequelize 足够智能(并且您的数据库支持任何进程锁定)来对操作进行排队并处理重复写入。
upsert如果您确实希望对orderId(这似乎很合理,但您可能会意识到特定设置中的其他注意事项)有唯一的约束,则此处的操作会很有帮助。
选项 2:使用队列。这显然更复杂,因此请仔细权衡您的用例是否值得额外的工作。不要立即将数据写入数据库,而是将 webhook 数据放入队列(例如先进先出 FIFO 队列)中。理想情况下,您需要选择一个支持重复数据删除的队列,以便保证退出的消息是唯一的,但这会推断状态,并且通常依赖于某种数据库,这就是一开始的问题。
队列为您做的最重要的事情是它将序列化消息,以便您可以一次处理一个消息(而不是同时启动多个数据库操作)。当您从队列中读取消息时,可以将数据更新插入数据库。如果 webhook 持续触发并且更多消息进入队列,那很好,因为队列会强制将它们全部排列成单个文件,并且您可以一次处理每个插入。您会知道每个数据库操作在继续处理下一条消息之前都已完成,因此您永远不会“猛击”数据库。换句话说,将队列放在数据库前面将允许数据库在数据库准备就绪时处理数据,而不是在 Webhook 调用时处理数据。
这里队列的想法类似于信号量完成的任务。请注意,您的数据库接口可能已经在底层实现了一种队列/池,因此请仔细权衡此选项:不要重新发明轮子。
希望这些想法有用。
| 归档时间: |
|
| 查看次数: |
2159 次 |
| 最近记录: |