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

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

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

我在我的开发机器上本地运行服务器。我有可以成功订阅提要的代码,我通过直接在 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 服务器,它会自动排队,而且非常轻量级。

标签: ruby-on-rails ruby concurrency websub superfeedr


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多