提问人:Josh 提问时间:11/14/2023 最后编辑:Josh 更新时间:11/14/2023 访问量:71
信号量Slim vs Hangfire
SemaphoreSlim vs Hangfire
问:
我有一个解决方案,可以接收处理订单的请求。条件是,如果订单状态为“已付款”,则处理订单。其他订单状态包括“已发货”和“待处理”。
示例代码在这里
var orderDetails = await _dbContext.Orders.FirstOrDefaultAsync(s => s.Id == orderId);
string errMsg = string.Empty;
if (orderDetails == null)
{
errMsg = "Invalid order";
//Handle invalid order id case
return new ServiceTypeResponse<SimpleOrderDetailsResponseModel>
{
Data = null,
Errors = new List<string> { errMsg },
ResponseMessage = errMsg,
StatusCode = 400,
Success = false
};
}
if (orderDetails.Status == OrderStatus.Fullfilled)
{
//handle already fulfilled order case
errMsg = "This order has already been fulfilled";
return new ServiceTypeResponse<SimpleOrderDetailsResponseModel>
{
Data = new SimpleOrderDetailsResponseModel(orderDetails),
Errors = null,
ResponseMessage = errMsg,
StatusCode = 200,
Success = true
};
}
if (orderDetails.Status == OrderStatus.Paid)
{
//1. process the order here and give value to the customer
//2. Change the status of the order to Fulfilled
}
return;
}
我试图避免多个线程向此解决方案发送请求以处理订单的争用条件。 为了避免从多个线程中多次处理订单,我正在考虑实现 SemaphoreSlim 或使用 Hangfire 对请求进行排队。
尽管有人在评论中建议在数据库上使用乐观并发锁定,但在这种情况下,乐观并发的问题在于乐观并发不会阻止记录被另一个线程读取。因此,在一个线程从数据库中读取记录并将订单状态读取为“已付款”后,在处理订单并可能调用第三方服务来履行订单之前,在将记录更新为“已履行”之前,另一个线程不妨读取记录并调用第三方服务并第二次履行订单,然后再尝试更新记录。我这个cae,虽然第二个线程无法更新订单的状态,但它会完成订单两次。
考虑到性能和最佳实践,避免多次处理订单的最佳方法是什么
问候
答:
1赞
Magnus
11/14/2023
#1
在具有所需隔离级别的事务中,运行以下命令(而不是 ):_dbContext.Orders.FirstOrDefaultAsync(...)
UPDATE orders
SET Status = 'Processing'
OUTPUT deleted.*
WHERE id = @orderId AND Status = 'Paid'
deleted.*
将返回更新前的实体,并将具有 status ,并将其映射到您的类。然后继续执行其余代码。如果指定的订单没有状态已支付,则返回为止的空集。Paid
orderDetails
评论