ActiveRecord 创建期间的 HTTP 请求

Posted

技术标签:

【中文标题】ActiveRecord 创建期间的 HTTP 请求【英文标题】:HTTP request during ActiveRecord creation 【发布时间】:2013-11-16 00:02:43 【问题描述】:

我正在尝试订阅 superfeedr 上的 pubsubhubbub (pshb) 订阅源。 pshb 协议的工作方式是

    您向中心发送 POST 请求订阅提要并提供回调 hub 向您的回调发送 GET 以验证您的订阅意图 你回答说是的,我确实想订阅 集线器响应订阅验证

我在我的开发机器上本地运行服务器。我有可以成功订阅提要的代码,我通过直接在 rails 控制台中执行它来测试它。我现在创建了一个 Feed ActiveRecord 模型,并希望在每次创建新的 Feed 记录时自动订阅。我在 Feed 模型中添加了一个 ActiveRecord 回调

after_create :subscribe_feed

现在,当我创建一个活动记录时,我看到正确的 HTTP 请求发出,然后出现长时间挂起(大约 5 秒,日志中没有任何反应),然后来自 pshb 服务器的响应说我的回调可以无法到达。

这是日志(我添加的数字作为参考点)

(1)   (0.1ms)  begin transaction
(2)  SQL (4.4ms)  INSERT INTO "feeds" ("created_at", "updated_at", "url") VALUES (?, ?, ?)  [["created_at", Fri, 15 Nov 2013 23:08:39 UTC +00:00], ["updated_at", Fri, 15 Nov 2013 23:08:39 UTC +00:00], ["url", "http://push-pub.appspot.com/feed"]]

(3) pshb subscribe parameters: :headers=>"Accept"=>"application/json", :body=>"hub.mode"=>"subscribe", "hub.verify"=>"sync", "hub.callback"=>"http://...myserver.../pub_sub/callback", "hub.topic"=>"http://push-pub.appspot.com/feed", "hub.verify_token"=>"superfeedtest", "format"=>"json"

(4) # ABOUT 5 SECOND WAIT

(5) Subscribe Response: #<HTTParty::Response:0x7fd2180cd978 parsed_response="Your callback couldn't be reached.\n", @response=#<Net::HTTPUnprocessableEntity 422 Unprocessable Entity readbody=true>, @headers="server"=>["nginx/0.8.52"], "date"=>["Fri, 15 Nov 2013 23:08:44 GMT"], "content-type"=>["text/plain; charset=utf-8"], "connection"=>["close"], "status"=>["422 Unprocessable Entity"], "x-runtime"=>["10057"], "content-length"=>["35"], "set-cookie"=>["_superfeedr_session=BAh7BzoMdXNlcl9pZGkC%2BIY6D3Nlc3Npb25faWQiJTBiMDExZGYzNzU4Mjk0MTMxNjc4NmE0OTg3MDhlMjJk--85d29756ae4b5ae9464630741372af7656f3894b; path=/; HttpOnly"], "cache-control"=>["no-cache"], "pubsubhubbub-version"=>["0.3"]>

(6)   (7.2ms)  commit transaction
Redirected to http://67.180.177.165/feeds/28
Completed 302 Found in 10695ms (ActiveRecord: 11.6ms)

(7) Started GET "/pub_sub/callback?hub.challenge=437c4b3b47aa1dbf4072a2d8abb5c39a&hub.lease_seconds=315360000&hub.mode=subscribe&hub.topic=http%3A%2F%2Fpush-pub.appspot.com%2Ffeed&hub.verify_token=superfeedtest" for 173.255.193.75 at 2013-11-15 15:08:50 -0800

您可以看到,在响应之后,提交事务发生(6),然后来自 phsb 服务器要求验证的 GET 进入(7)。所以集线器可以到达我的回调,但由于某种原因,我直到超时后才收到集线器的 GET?

我是 Rails 的新手,所以不确定事情是如何工作的,但我猜想在 ActiveRecord 创建过程中并发请求会发生一些事情。订阅独立工作,但不是在 ActiveRecord 创建期间,因为我在 after_create 中设置了它。

如果您想在创建 ActiveRecord 条目时处理对 3rd 方服务器的 HTTP 请求,正确的方法是什么?

注意** 在 superfeedr api 中,您可以指定异步发生的验证意图。当我将其指定为异步时,我确实得到了成功响应,但订阅似乎仍然没有在 superfeedr 的集线器上创建。我会就这个问题直接联系 superfeedr,但总的来说,我想知道如何为没有异步选项的 API 处理这种情况。

【问题讨论】:

我不会因为 GET 请求而占用 ActiveRecord 进程。如果您的请求花费的时间太长,您的代码就会挂起,这对您的服务器和您拥有的任何用户都是不利的。人们甚至可以通过提供他们知道需要一段时间的虚假条目来拒绝您。相反,将 URL 写入您的数据库,然后启动一个仅处理该订阅过程的线程,然后退出。或者,查看 AMQP/RabbitMQ 之类的东西并编写一个为您处理工作的节点;它不会挂起你的 Rails 服务器,它会自动排队,而且非常轻量级。 【参考方案1】:

这个问题是 Rails 在“开发”环境中的一个众所周知的问题,它只允许一个并发的 HTTP 请求。由于您在一个 HTTP 请求期间执行您的 after_create :subscribe_feed,因此当 Superfeedr 尝试验证您的意图时,它会在第一个请求期间向您的输入发出第二个请求。验证将挂起,直到订阅请求完成...触发某种死锁。

解决方案很简单:订阅时使用hub.verify=async 参数,Superfeedr 将首先关闭订阅请求(状态为 202)并然后发出意图验证。

您也可以删除 hub.verify 参数,因为它默认是异步的。

【讨论】:

以上是关于ActiveRecord 创建期间的 HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章

使用 ActiveRecord,有没有办法在 after_update 期间获取记录的旧值

ruby 使用多态数据库模型自动创建Active Record关联:http://api.rubyonrails.org/classes/ActiveRecord/Associat

find_or_create ActiveRecord :: RecordNotUnique rescue retry无法正常工作

请安装 mysql 适配器 'gem install activerecord-mysql-adapter'

ActiveRecord、has_many :through 和多态关联

创建一个简单的“ORM/ActiveRecord”模式