2012-06-28 2 views
2

안녕하세요. 나는 얇은 문서를 읽었으며 이벤트 머신에 합리적으로 새로운 것이지만 Deferrables의 작동 방식을 알고 있습니다. 나의 목표는 시체가 연기되고 부분별로 스트리밍 될 때 Thin이 작동하는 방식을 이해하는 것입니다.씬 (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에 저장된 블록으로 실행되면 몸체를 전송할 때마다 각각의 데이터 청크가 수신되지만, 해당 블록을 호출 할 때 yield 또는 call이 호출되면 어떻게됩니까? 전송시 단일 메시지.

나는 무슨 일이 일어나고 있는지 이해하기에 충분할만큼 클로저를 이해하지 못한다고 생각합니다. 이것에 대한 도움을 주시면 감사하겠습니다.

감사합니다.

답변

2

좋아 각각의 블록이 어떻게 작동하는지 알았습니다. post_init

얇은

연결이 들어올 때 @request@response 객체를 생성하는 것으로 보인다. 응답 객체는 each 방법에 응답 할 필요가있다. 이것은 우리가 재정의하는 방법입니다.

env['async.callback']

는 데이터가 실제로 응답 객체의 각이 정의하는 방법이

 

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

과 같은 연결로 전송되는 connection.rb 클래스 메서드에 post_process라는 방법에 할당 된 폐쇄입니다

 

def each 
     yield head 

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

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

우리의 env [ 'async.callback']은 기본적으로 method(:post_process)을 통해 액세스되는 connection.rb 클래스에 정의 된 post_process이라는 메서드입니다. @response 객체에 대한 액세스가 포함 된 클로저처럼 처리해야합니다. 원자로가 시작되면 먼저 헤더를 생성하는 next_tick에 헤더 데이터를 보내지 만이 시점에서는 본문이 비어 있으므로 아무 것도 산출되지 않습니다. add_timers 화재 트리거 가져옵니다 post_process은 우리가 완전히 브라우저 (또는 어디든지)

body.call(["Wooah..."])를 사용하여 제공 한 데이터를 보낼 때이 우리의 each 방법 후

그래서 @response 객체에 의해 소유 된 구현을 오버라이드 (override) macournoyer의 두려움과 얇게하는 팀. 이것이 어떻게 작동하지 않는다고 생각하면 제 이해를 교정하십시오.