我在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

然后我有一个控制器来处理回调:
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)

我们查过了,身份证是正确的。更疯狂的是,我们在创建模型时输入了一个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在保存文本消息的数据库事务中处理。因此,命中另一个控制器的回调无法读取文本消息。在数据库事务中进行外部调用不是一个好主意,因为事务会在缓慢的外部请求执行的整个过程中阻塞数据库的部分。
简单的解决方案是用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

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

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

10-17 01:50