Rails事务死锁或其他事情

时间:2017-09-21 03:57:13

标签: ruby-on-rails transactions locking pessimistic-locking

我的Rails应用中有UserOrderContestPosition个模型。 UserOrder之间存在多对多关系,PositionOrderUserContest之间存在一对多关系

我的订单处理器服务采用execute方法处理订单。为了防止竞争条件,我在内部使用lock!进行交易。

问题在于,当我同时在参数中使用相同的顺序调用两个或更多execute方法时,我有时会遇到死锁。最奇怪的是第一种方法开始执行而第二种方法正在等待解锁。一切如预期。但我的第一个方法(正在执行)是锁定在中间。更奇怪的是,该方法锁定了不处理任何锁定记录的行。如果我评论一些不相关的行,并且有时(并非总是)它会锁定在没有改变甚至没有使用任何锁定记录的行上,那么方法永远执行的行可以随机改变。

这是我的execute方法

  user = order.user
  contest = user.contest
  ActiveRecord::Base.transaction do

    # the second method awaiting here as excpected
    order.lock! 

    # some processing stuff here like
    order.executed = true

    position = find_or_create_position(order)
    position.lock!

    # .where.not(id: order.id) just in case to ignore locked row
    # but based on business logic it can't really be anyway.
    #
    # Plus it is not seems like the reason because 
    # if I comment this and the next lines deadlock occurs later
    open_orders = user.orders.open.where.not(id: order.id)

    # commonly method stops here
    closed_orders = close_open_orders!(order, price, open_orders)

    # method stops here if I comment two lines above
    order.save!

    # I left this line because as I remember once 
    # after some random changes like commenting some lines 
    # I got method stopped even here
    commission = contest.commission * order.count
    closed_orders.each { |closed_order| closed_order.save! }

    # here some position processing and finally
    position.save!

    user.lock!
    # and user processing
    user.save!
  end

通过在注释中处理,我的意思是指向记录的赋值属性。

所以这是我的close_open_orders!方法

的开头
  rest_count = order.count

  # here it stops. each just stops without any iteration. 
  open_orders.each do |open_order|

但我不认为问题出在each声明中,因为正如我所说,如果我忽略这种方法,我会陷入僵局。

当只执行一个方法时,一切正常。 我也可以附上pg日志,但我没有看到任何死锁:两个选择更新的订单。而不是选择user.orders.open.where.not(id: order.id)和那些全部。之后无关(或不?):

03:58:13 [21231-1] LOG:  statement: set client_encoding to 'UTF8'
03:58:13 [21231-2] LOG:  statement: set client_encoding to 'unicode'
03:58:13 [21231-3] LOG:  statement: SET client_min_messages TO 'warning'

如果需要,我可以添加更多pg日志。

UPD 我使用sidekiq异步执行作业

0 个答案:

没有答案