Ruby on rails Queing

时间:2016-03-23 07:51:26

标签: ruby-on-rails-4

有2个apis暴露给客户和商家..商家和客户都将使用相同的交易ID 打到他们各自的api。无论谁先来,我应该在db中创建具有交易ID和商家详细信息(如果商家是第一个)和第二个如果客户来了我应该用商家创建记录的交易ID更新记录的客户详细信息。

如何通过一次接受10,000次请求命中来处理它。它应该没有任何问题回复?请告诉我们如何在rails中实施,是否可行。

提前谢谢..

2 个答案:

答案 0 :(得分:0)

我正在嘲笑这个作为答案,但听起来你只需要锁定。改变你的表格,包括一个名为'owned_by'的列(或类似的东西)。

每当您的实例需要修改记录时,请让它发出如下更新:

UPDATE table_name SET owned_by = IF(owned_by IS NULL, 'uniq_id', owned_by) WHERE id = 1;

IF语句可以防止它在检查之间被锁定时窃取锁定。

然后重新查询该行,如果uniq_id设置为当前线程uniq_id,则表示您可以安全地编写,否则让它以增量方式休眠并重新查询,直到记录锁定释放为止。如果可以在没有锁的情况下完成某些事情,那就让它忽略该字段。工作流程看起来像这样(sudo代码):

def uniq_id
  rand() #probably want something better here
end

def trylock_row
  "UPDATE table_name SET owned_by = IF(owned_by IS NULL, '#{uniq_id}', owned_by) WHERE id = #{id};"
end

def release_lock
  "UPDATE table_name SET owned_by = IF(owned_by == '#{uniq_id}', NULL, owned_by) WHERE id = #{id};"
end

def reget_row
  "SELECT * FROM table_name WHERE id = #{id}"
end

def issue_update something
  r = self
  while(r.owned_by != uniq_id){
    if r.owned_by.nil?
      trylock_row
      r = reget_row
      break if r.owned_by == uniq_id
    end
    sleep(0.25) #arbitrary, keep it small
    r = reget_row
  }
  #issue_updates
  release_lock #Really should be in a ensure block just in case
end

答案 1 :(得分:0)

我将提供另一种处理方法。

正如Camway在回答中提到的,锁定是一种方法。这是一些额外的资源:

http://thelazylog.com/understanding-locking-in-rails-activerecord/

https://www.leighhalliday.com/avoid-race-conditions-with-postgres-locks

另一种处理方法是使用数据库级约束。虽然Rails级别竞争条件可能导致数据完整性失败,但在数据库级别上,记录仍然是一个接一个地插入(这是写入比读取慢的原因之一)。

因此,您只需在其中一个字段上添加唯一索引约束即可。由于您没有描述客户和商家如何匹配transaction_id,因此我无法告诉哪个字段添加约束。但你可以这样:

def find_or_create
  # pseudocode here
  transaction = Transaction.find_by_condition(...)
  return transaction if transaction

  Transaction.create!(...)
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid => e
  log_error
  retry
end

我在生产中使用它,我们服务数百万个db事务没有问题。救援区通常只会执行几次,因为大部分时间你会找到记录并立即归还。