如何在Thin中实现ActionController::Live的流式传输?

6

问题

你能否使用thinActionController::Live实现服务器端事件(SSE)和长轮询? 如果可以,如何实现?

背景

虽然标题重复了如何在Thin和Ruby 2上实现Rails 4 ActionController::Live流媒体功能?,但 OP 提出了两个问题,而这个问题从未得到回答。

许多其他帖子建议您可以通过exec thin start --threaded启动thin来使用服务器端事件(sse): Heroku是否支持ActionController::Live?Puma是唯一的多线程Rails 4 HTTP服务器吗?,Aaron的经典文章http://tenderlovemaking.com/2012/07/30/is-it-live.html和 Ryan永恒可靠的http://railscasts.com/episodes/401-actioncontroller-live?view=asciicast。但即使我复制了Railscast的示例,也无法使用thin使其正常工作。

我的尝试

# ----------------------------------------------------------------
# file: config/routes.rb
Rails.application.routes.draw do

  resources :widgets do
    collection do
      get 'events'              # SSE test
    end
  end
end

_

# ----------------------------------------------------------------
# file: config/environments/development.rb
Rails.application.configure do
    ... snip ...
    # see http://tenderlovemaking.com/2012/07/30/is-it-live.html
    config.preload_frameworks = true
    config.allow_concurrency = true
end

_

# ----------------------------------------------------------------
# file: app/controllers/widgets_controller.rb
class WidgetsController < ApplicationController
  include ActionController::Live

  # GET /widgets/events
  # see http://railscasts.com/episodes/401-actioncontroller-live?view=asciicast
  def events
    # SSE expects the `text/event-stream` content type
    response.headers['Content-Type'] = 'text/event-stream'
    3.times do |n|
      response.stream.write "#{n}...\n\n"
      sleep 2
    end
  ensure
    response.stream.close
  end

end

_

# ----------------------------------------------------------------
# Gemfile
source 'https://rubygems.org'

gem 'rails', '4.1.8'
gem 'pg'
... snip ...
gem 'thin'

运行它

在 A 终端窗口中:

$ bundle install
Chalcedony[~/Projects/heroku-sample/widget-worker]$ thin start --threaded --trace
Using rack adapter
Thin web server (v1.6.3 codename Protein Powder)
Tracing ON
Maximum connections set to 1024
Listening on 0.0.0.0:3000, CTRL+C to stop

然后在 shell 窗口 B 中:

$ curl --no-buffer localhost:3000/widgets/events

在 Shell 窗口 A 中,我看到请求和响应以一秒的间隔被输出(0...1... 以及 2... 之间有一秒的延迟)。这很好。
GET /widgets/events HTTP/1.1
User-Agent: curl/7.37.1
Host: localhost:3000
Accept: */*


HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
Content-Type: text/html; charset=utf-8
X-Request-Id: 95e64eb6-ee21-4e97-a33a-dbf579b3027c
X-Runtime: 0.066925
Connection: close
Server: thin


0... <delay...>


1... <delay...>


2... <delay...>

在Shell窗口B中,打印输出被延迟并一次性全部出现。当我在Chrome浏览器中查看页面时,也有相同的情况发生。我是否没有正确配置一些设置?
$ rake about
About your application's environment
Ruby version              2.1.4-p265 (x86_64-darwin14.0)
RubyGems version          2.2.2
Rack version              1.5
Rails version             4.1.8
JavaScript Runtime        JavaScriptCore
Active Record version     4.1.8
Action Pack version       4.1.8
Action View version       4.1.8
Action Mailer version     4.1.8
Active Support version    4.1.8
Middleware                Rack::Sendfile, ActionDispatch::Static, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fb0cb4ae1a0>, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::Head, Rack::ConditionalGet, Rack::ETag
Environment               development
Database adapter          postgresql
Database schema version   20141213003938

P.P.S.

现在你可能会想:“为什么你不像其他人一样使用puma呢?” 这是个好问题。 目前,由于我还没有找到原因,无法在我的电脑上构建puma gem。同时,在我的大多数heroku部署的应用中,我一直在使用thin,所以我对它很熟悉。 如果我无法让thin正常工作,我将更加努力地构建puma


我的早期评论是不正确的(或者可能是正确的,但最好的情况下是基于错误的原因)。 - Chuck Vose
好的,仔细阅读后,我觉得curl上的连接头应该不应该是close,对于流式事件来说。你描述的效果就像根本没有流式传输,而是等待所有数据通过然后刷新。我没有答案,但也许这会有所帮助。我迫切地等待着有更多经验的人来解答! - Chuck Vose
1个回答

3

很遗憾,您不能在Thin中使用AC::Live。这里是Mark的解释以及可替代的方法。


1
简单的回答。将 gem 'thin' 替换为 gem 'puma',就可以了。 - Mike A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接