From acb6848468bc4ec035201b23af9affeb8279711f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 27 Jul 2012 15:54:11 -0700 Subject: [PATCH] threads can wait on responses to be committed --- actionpack/lib/action_controller/test_case.rb | 1 + .../lib/action_dispatch/http/response.rb | 25 ++++++++++++++++++- actionpack/test/dispatch/response_test.rb | 9 +++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 5f50bf5de6..eb7194ebaf 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -226,6 +226,7 @@ module ActionController @block = nil @length = 0 @body = [] + @committed = false @charset = @content_type = nil @request = @template = nil end diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index cc46f9983c..d590a23a81 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -2,6 +2,7 @@ require 'digest/md5' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/class/attribute_accessors' +require 'monitor' module ActionDispatch # :nodoc: # Represents an HTTP response generated by a controller action. Use it to @@ -62,12 +63,17 @@ module ActionDispatch # :nodoc: include Rack::Response::Helpers include ActionDispatch::Http::Cache::Response + include MonitorMixin def initialize(status = 200, header = {}, body = []) + super() + self.body, self.header, self.status = body, header, status @sending_file = false - @blank = false + @blank = false + @cv = new_cond + @committed = false if content_type = self[CONTENT_TYPE] type, charset = content_type.split(/;\s*charset=/) @@ -80,6 +86,23 @@ module ActionDispatch # :nodoc: yield self if block_given? end + def await_commit + synchronize do + @cv.wait_until { @committed } + end + end + + def commit! + synchronize do + @committed = true + @cv.broadcast + end + end + + def committed? + synchronize { @committed } + end + def status=(status) @status = Rack::Utils.status_code(status) end diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index 82d1200f8e..500056b56b 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -5,6 +5,15 @@ class ResponseTest < ActiveSupport::TestCase @response = ActionDispatch::Response.new end + def test_can_wait_until_commit + t = Thread.new { + assert @response.await_commit + } + @response.commit! + assert @response.committed? + t.join + end + def test_response_body_encoding body = ["hello".encode('utf-8')] response = ActionDispatch::Response.new 200, {}, body