ruby-on-rails - Ruby on Rails 中的竞争条件

标签 ruby-on-rails ruby postgresql heroku race-condition

我在 Heroku 上遇到了一个奇怪的错误,我认为这可能是一个竞争条件,我正在寻找解决它的任何建议。

我的应用程序有一个模型,该模型在创建后调用外部 API(Twilio,如果您好奇的话)。在这个调用中,它传递一个 url,一旦第三方完成他们的工作就会被回调。像这样:

class TextMessage < ActiveRecord::Base
   after_create :send_sms

   def send_sms
     call.external.third.party.api(
       :callback => sent_text_message_path(self)
     )
   end
end

然后我有一个 Controller 来处理回调:

class TextMessagesController < ActiveController::Base
  def sent
    @textmessage = TextMessage.find(params[:id])
    @textmessage.sent = true
    @textmessage.save
  end
end

问题是第三方报告他们在回调中收到 404 错误,因为模型尚未创建。我们自己的日志证实了这一点:

2014-03-13T18:12:10.291730+00:00 app[web.1]: ActiveRecord::RecordNotFound (Couldn't find TextMessage with id=32)

我们检查过,ID 是正确的。更疯狂的是,我们在创建模型时加入了一个 puts 来记录,这就是我们得到的:

2014-03-13T18:15:22.192733+00:00 app[web.1]: TextMessage created with ID 35.
2014-03-13T18:15:22.192791+00:00 app[web.1]: ActiveRecord::RecordNotFound (Couldn't find TextMessage with id=35)

注意时间戳。这些事情似乎相隔 58 毫秒发生,所以我认为这是一个竞争条件。我们正在使用 Heroku(至少用于暂存),所以我认为问题可能出在他们的虚拟 Postgres 数据库上。

有没有人遇到过这种问题?如果是这样,您是如何解决的?有什么建议吗?

最佳答案

after_create 在保存文本消息的数据库事务中处理。因此,命中另一个 Controller 的回调无法读取文本消息。在数据库事务中进行外部调用不是一个好主意,因为事务会在缓慢的外部请求占用的整个时间内阻塞部分数据库。

最简单的解决方案是将 after_save 替换为 after_commit(参见:http://apidock.com/rails/ActiveRecord/Transactions/ClassMethods/after_commit)

由于回调往往变得难以理解(并可能在测试时导致问题),我更愿意通过调用另一个方法来明确调用。也许是这样的:

# use instead of .save 
def save_and_sent_sms
  save and sent_sms
end

也许你想在后台发送短信,这样它就不会减慢用户的网络请求。搜索 gem delayed_job 或 resque 以获取更多信息。

关于ruby-on-rails - Ruby on Rails 中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22389287/

相关文章:

javascript - Rails Ajax : Search still refreshing the page after click

ruby-on-rails - Tesseract 适用于仅包含文本的图像 - 裁剪图像以仅从图像中获取文本部分

ruby-on-rails - 切换 Ruby on Rails 数据库

ruby - 使 Ruby 记录器自动刷新

SQL 连接子查询问题/性能

java - 告诉 Hibernate 仅让数据库在值为 null 时生成值

database - Postgres 约束表的写入和删除顺序

ruby-on-rails - 如何将 Base 64 图像上传到 Rails 回形针

ruby-on-rails - 在 macOS Catalina 上安装 Ruby 2.0.0 的问题

ruby - 如何在 Ruby 中重新排序 XML 文件