如何仅允许一个请求执行诉讼并拒绝所有其他并发请求?
当多个并发请求尝试调用控制器拒绝操作时。在竞赛条件下,它多次生成相同的注释
,尽管request> request
和order
被拒绝。但是在种族条件下,请求
无法识别订单
已经被其中一个请求
之一拒绝,因为所有这些过程都在很少的时间内执行订单
更改为拒绝。为了避免此竞赛条件问题,我已锁定请求
和订单
在DB行级别。但这不起作用。这是我的示例代码:
我使用Ruby 2.5.8,Rails 5.0.7。
我的模型
- 订单有许多请求
- 请求有一个批准者
class Request < ApplicationRecord
def self.reject_request(key)
request = Request.where(:reject_key => key).first
order = request&.order
raise ActiveRecord::Rollback if request.blank? || order.blank?
raise ActiveRecord::Rollback if request.rejected? || order.rejected?
order.lock!
request.lock!
request.status = 'rejected'
request.save!
order.update(status: 'rejected')
true
end
end
我的控制器
class OrdersController < ApplicationController
def reject
@request ||= Request.find_by(reject_key: params[:reject_key])
@order = @request&.purchase_order
ActiveRecord::Base.transaction do
rejected = Request.reject_request(params[:reject_key])
@order.comments.create(comment: "Order rejected by approver: #{@request.approver.name}") if rejected
if rejected
redirect_to root_path, notice: 'Rejected'
else
redirect_to root_path, notice: 'Try again!'
end
end
end
end
问题
应该只有一个正确的评论如下所示。
批准者拒绝的订单:乔(正确)
批准者拒绝的订单:杰克(不正确)
批准者拒绝的订单:乔(不正确)
批准者拒绝的订单:杰克(不正确)
当拒绝行动执行拒绝时,它在执行拒绝时工作通过应用程序链接。但是,当多个请求通过多线程流程运行时,它就无法正常工作。如何仅允许一个请求执行该动作并拒绝所有其他行动?任何反馈都将不胜感激,谢谢!
When multiple concurrent requests try to call controller reject action. In race conditions, it generates same comments
multiple times, although one of the request
and order
is rejected. But in race conditions, request
cannot identify order
was already rejected by one of the request
because all these processes executes in very little amount of time before order
changed to reject. To avoid this race condition issue, I have locked request
and order
in DB row level. But it's not working. Here are my sample codes:
I am using Ruby 2.5.8, Rails 5.0.7.
My Model
- Order has many requests
- Request has one approvers
class Request < ApplicationRecord
def self.reject_request(key)
request = Request.where(:reject_key => key).first
order = request&.order
raise ActiveRecord::Rollback if request.blank? || order.blank?
raise ActiveRecord::Rollback if request.rejected? || order.rejected?
order.lock!
request.lock!
request.status = 'rejected'
request.save!
order.update(status: 'rejected')
true
end
end
My Controller
class OrdersController < ApplicationController
def reject
@request ||= Request.find_by(reject_key: params[:reject_key])
@order = @request&.purchase_order
ActiveRecord::Base.transaction do
rejected = Request.reject_request(params[:reject_key])
@order.comments.create(comment: "Order rejected by approver: #{@request.approver.name}") if rejected
if rejected
redirect_to root_path, notice: 'Rejected'
else
redirect_to root_path, notice: 'Try again!'
end
end
end
end
Problem
There should be only one correct comment, but there are more incorrect comments generated as shown below.
Order rejected by approver: Joe (correct)
Order rejected by approver: Jack (not correct)
Order rejected by approver: Joe (not correct)
Order rejected by approver: Jack (not correct)
It's working when reject action is executed by clicking on reject link through application. But when multiple requests are running through multi-threaded process, then it does not work as I described above. How to allow only one request to perform the action and reject all other actions? Any feedback would be appreciated, thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在检查状态之前,您需要锁定订单。
如果2个并发请求执行检查
请求。 ||订单。拒绝?
与您的解决方案同时获得false
,并在锁定下进行。更改您的模型
You need to lock an order before checking it's status.
If 2 concurrent requests execute check for
request.rejected? || order.rejected?
simultaneously with your solution, both getsfalse
and proceed consequentially under the lock.Changes for your model