2

こんにちは私はThinのドキュメントを読んでいて、eventmachineはかなり新しいですが、Deferrablesがどのように機能するかを知っています。私の目標は、体が部分的に延期されてストリーミングされるときに、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

call私がはっきりと理解していない部分は、とメソッドのDeferrableBodyクラス内で何が起こるかeachです。

タイマーが@body_callbackに格納されたブロックとして起動すると、それぞれがデータのチャンクを受信し、本体でsuccessが呼び出されると本文を送信しますが、これらのブロックでisyieldまたは call呼び出されると、送信時にどのように単一のメッセージになりますか。

何が起こっているのかを理解するのに十分なクロージャを理解していないように感じます。これに関する助けをいただければ幸いです。

ありがとうございました。

4

1 に答える 1

2

わかりました。各ブロックがどのように機能するかを理解したと思います。

Thin onは、接続が確立されたときにandオブジェクトpost_initを生成しているようです。応答オブジェクトはメソッドに応答する必要があります。これはオーバーライドするメソッドです。@request@responseeach

これは、クラスメソッドでenv['async.callback']呼び出されるメソッドに割り当てられるクロージャであり、データは実際には次のように接続に送信されます。post_processconnection.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']は基本的に、@responseオブジェクトへのアクセスを含むクロージャーのようにメソッドを処理できるようにすることでpost_processアクセスされるconnection.rbクラスで定義されたメソッドです。method(:post_process)リアクターが起動すると、最初にヘッダーデータがnext_tickヘッドを生成する場所に送信されますが、この時点では本体が空であるため、何も生成されません。

この後、このメソッドはオブジェクトeachが所有する古い実装をオーバーライドするため、トリガーされた火災が発生すると、を使用して提供したデータがブラウザー(または任意の場所)に送信されます。@responseadd_timerspost_processbody.call(["Wooah..."])

完全にmacournoyerとチームが痩せようとしていることに畏敬の念を抱いています。これがどのように機能するかではないと思われる場合は、私の理解を訂正してください。

于 2012-06-28T16:26:29.573 に答える