ruby - 瘦异步应用程序示例如何缓冲对主体的响应?

标签 ruby rack eventmachine thin

您好,我一直在阅读有关 Thin 的文档,而且我对 eventmachine 相当陌生,但我知道 Deferrable 的工作原理。我的目标是了解当正文被延迟并逐部分流式传输时 Thin 是如何工作的。

以下是我正在处理并试图理解的示例。


class DeferrableBody
  include EventMachine::Deferrable

  def call(body)
    body.each do |chunk|
      @body_callback.call(chunk)
    end

   # @body_callback.call()
  end

  def each &blk
    @body_callback = blk
  end

end

class AsyncApp

  # This is a template async response. N.B. Can't use string for body on 1.9
  AsyncResponse = [-1, {}, []].freeze
  puts "Aysnc testing #{AsyncResponse.inspect}"

  def call(env)

    body = DeferrableBody.new    

    # Get the headers out there asap, let the client know we're alive...
    EventMachine::next_tick do
       puts "Next tick running....."
       env['async.callback'].call [200, {'Content-Type' => 'text/plain'}, body] 
     end

    # Semi-emulate a long db request, instead of a timer, in reality we'd be 
    # waiting for the response data. Whilst this happens, other connections 
    # can be serviced.
    # This could be any callback based thing though, a deferrable waiting on 
    # IO data, a db request, an http request, an smtp send, whatever.
    EventMachine::add_timer(2) do
      puts "Timer started.."
      body.call ["Woah, async!\n"]

      EventMachine::add_timer(5) {
        # This could actually happen any time, you could spawn off to new 
        # threads, pause as a good looking lady walks by, whatever.
        # Just shows off how we can defer chunks of data in the body, you can
        # even call this many times.
        body.call ["Cheers then!"]
        puts "Succeed Called."
        body.succeed
      }
    end

    # throw :async # Still works for supporting non-async frameworks...
    puts "Async REsponse sent."
    AsyncResponse # May end up in Rack :-)
  end

end

# The additions to env for async.connection and async.callback absolutely 
# destroy the speed of the request if Lint is doing it's checks on env.
# It is also important to note that an async response will not pass through 
# any further middleware, as the async response notification has been passed 
# right up to the webserver, and the callback goes directly there too.
# Middleware could possibly catch :async, and also provide a different 
# async.connection and async.callback.

# use Rack::Lint
run AsyncApp.new

我不太清楚的部分是 DeferrableBody 类中的 calleach 方法中发生的情况。

我知道,一旦计时器作为存储在 @body_callback 中的 block 触发,每个都会收到数据 block ,并且当在主体上调用成功时,它会发送主体,但何时是 yieldcall 调用这些 block ,发送时它如何变成单个消息。

我觉得我对闭包的理解还不足以理解正在发生的事情。如果有任何帮助,我们将不胜感激。

谢谢。

最佳答案

好吧,我想我已经弄清楚每个 block 是如何工作的了。

瘦于post_init似乎正在生成 @request@response连接进入时的对象。响应对象需要响应 each方法。这是我们重写的方法。

env['async.callback']是一个闭包,分配给名为 post_process 的方法在 connection.rb类方法,其中数据实际上发送到连接,如下所示


      @response.each do |chunk|        
        trace { chunk }
        puts "-- [THIN] sending data #{chunk} ---"
        send_data chunk
      end

如何定义每个响应对象


 def each
      yield head

      if @body.is_a?(String)
        yield @body
      else

        @body.each { |chunk| yield chunk }
      end
    end

所以我们的 env['async.callback'] 基本上是一个名为 post_process 的方法在通过method(:post_process)访问的connection.rb类中定义允许我们的方法像闭包一样处理,其中包含对 @response 对象的访问。当 react 器启动时,它首先发送 next_tick 中的 header 数据。它产生头部,但此时 body 是空的,所以没有产生任何东西。

此后我们的each方法覆盖 @response 拥有的旧实现反对所以当 add_timers开火post_process被触发的发送我们使用 body.call(["Wooah..."]) 提供的数据到浏览器(或任何地方)

完全敬畏 macournoyer 和致力于瘦身的团队。如果您觉得这不是它的工作原理,请纠正我的理解。

关于ruby - 瘦异步应用程序示例如何缓冲对主体的响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11245872/

相关文章:

ruby-on-rails - 安装mysql(2.9.1)时出错,Bundler无法继续

ruby-on-rails - Rails Thin 服务器无响应

ruby-on-rails - 验证 ssl 证书以验证访问我们私有(private) api 的服务?

ruby-on-rails - OSX Yosemite 更新破坏了 pow.cx

ruby - 在 CentOs 5 上安装 RubyGem

ruby-on-rails - 使用 Ruby/Rails 在当前周期中寻找容量

ruby-on-rails - 你如何生成一个 EventMachine "inside"一个 Rails 应用程序?

ssl - EventMachine 中的 TLS 连接如何工作?

ruby-on-rails - 为什么在私有(private)部分中声明委托(delegate)方法时是公开的?

ruby-on-rails - 如何通过 GMAIL API 发送带有 BCC header 的电子邮件?