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