async-rack 0.4.0.c → 0.4.0.d
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +43 -0
- data/lib/async_rack.rb +9 -4
- data/lib/async_rack/async_callback.rb +7 -2
- data/lib/async_rack/catch_async.rb +16 -0
- data/lib/async_rack/session/cookie.rb +1 -1
- data/lib/async_rack/session/memcache.rb +1 -1
- data/lib/async_rack/session/pool.rb +1 -1
- data/lib/async_rack/throw_async.rb +17 -0
- data/spec/async_rack/async_callback_spec.rb +1 -3
- metadata +5 -3
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# AsyncRack
|
2
2
|
|
3
|
+
## Note upfront
|
4
|
+
Still experimental. Feel free to play around.
|
5
|
+
|
6
|
+
## Introduction
|
3
7
|
So, have you been amazed by thin's `async.callback`? If not, [go](http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/) [check](http://github.com/raggi/async_sinatra) [it](http://github.com/raggi/thin/blob/async_for_rack/example/async_app.ru) [out](http://m.onkey.org/2010/1/7/introducing-cramp). Come back here when you start missing your middleware.
|
4
8
|
|
5
9
|
So what is the issue with Rack and `async.callback`? Currently there are two ways of triggering a async responds. The first is to `throw :async`, the latter to return a status code of -1 (even though thin and ebb do disagree on that). Opposed to what others say, I would recommend using `throw`, as it simply skips middleware not able to handle `:async`. Also, it works on all servers supporting `async.callback` – thin, ebb, rainbows! and zbatery – about the same and copes better with middleware that is unable to handle an async respond.
|
@@ -30,6 +34,45 @@ How does that work? Simple, whenever necessary, `async-rack` will replace `async
|
|
30
34
|
|
31
35
|
Note: This library only 'fixes' the middleware that ships with rack, not other rack middleware. However, you can use the included helper classes to easily make other libraries handle `async.callback`.
|
32
36
|
|
37
|
+
## What's in this package?
|
38
|
+
|
39
|
+
### Rack middleware made async-proof
|
40
|
+
This middleware now works well with `throw :async`:
|
41
|
+
|
42
|
+
* Rack::Chunked
|
43
|
+
* Rack::CommonLogger
|
44
|
+
* Rack::ConditionalGet
|
45
|
+
* Rack::ContentLength
|
46
|
+
* Rack::ContentType
|
47
|
+
* Rack::Deflater
|
48
|
+
* Rack::ETag
|
49
|
+
* Rack::Head
|
50
|
+
* Rack::Logger
|
51
|
+
* Rack::Runtime
|
52
|
+
* Rack::Sendfile
|
53
|
+
* Rack::ShowStatus
|
54
|
+
|
55
|
+
### Middleware that is async-proof out of the box
|
56
|
+
No changes where necessary for:
|
57
|
+
|
58
|
+
* Rack::Cascade
|
59
|
+
* Rack::Config
|
60
|
+
* Rack::Directory
|
61
|
+
* Rack::File
|
62
|
+
* Rack::MethodOverride
|
63
|
+
* Rack::Mime
|
64
|
+
* Rack::NullLogger
|
65
|
+
* Rack::Recursive
|
66
|
+
* Rack::Reloader
|
67
|
+
* Rack::Static
|
68
|
+
* Rack::URLMap
|
69
|
+
|
70
|
+
### Middleware not (yet) made async-proof
|
71
|
+
|
72
|
+
* Rack::Lint (might not check async responses)
|
73
|
+
* Rack::ShowExceptions (might not show exceptions for async responses)
|
74
|
+
* Rack::Lock (might raise an exception)
|
75
|
+
|
33
76
|
## How to make a middleware async-proof?
|
34
77
|
There are three types of middleware:
|
35
78
|
|
data/lib/async_rack.rb
CHANGED
@@ -13,13 +13,19 @@ module AsyncRack
|
|
13
13
|
module ExtensionMixin
|
14
14
|
::AsyncRack.extend self
|
15
15
|
def autoload(class_name, path)
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
if Rack.const_defined? class_name
|
17
|
+
require path
|
18
|
+
else
|
19
|
+
Rack.autoload class_name, path
|
20
|
+
super
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
25
|
+
# New middleware
|
26
|
+
autoload :CatchAsync, "async_rack/catch_async"
|
27
|
+
autoload :ThrowAsync, "async_rack/throw_async"
|
28
|
+
|
23
29
|
# Wrapped rack middleware
|
24
30
|
autoload :Chunked, "async_rack/chunked"
|
25
31
|
autoload :CommonLogger, "async_rack/commonlogger"
|
@@ -31,7 +37,6 @@ module AsyncRack
|
|
31
37
|
autoload :Head, "async_rack/head"
|
32
38
|
autoload :Lock, "async_rack/lock"
|
33
39
|
autoload :Logger, "async_rack/logger"
|
34
|
-
# autoload :Recursive, "async_rack/recursive"
|
35
40
|
autoload :Runtime, "async_rack/runtime"
|
36
41
|
autoload :Sendfile, "async_rack/sendfile"
|
37
42
|
autoload :ShowStatus, "async_rack/showstatus"
|
@@ -27,6 +27,10 @@ module AsyncRack
|
|
27
27
|
# Rack::FancyMiddleware # => AsyncRack::FancyMiddleware
|
28
28
|
# AsyncRack::FancyMiddleware.ancestors # => [AsyncRack::AsyncCallback::Mixin, Rack::FancyMiddleware, ...]
|
29
29
|
module AsyncCallback
|
30
|
+
def self.included(mod)
|
31
|
+
mod.send :include, Mixin
|
32
|
+
super
|
33
|
+
end
|
30
34
|
|
31
35
|
##
|
32
36
|
# Aliases a subclass on subclassing, but only once.
|
@@ -82,9 +86,9 @@ module AsyncRack
|
|
82
86
|
private
|
83
87
|
def setup_late_initialize(klass)
|
84
88
|
class << klass
|
85
|
-
alias create new
|
86
89
|
def new(*args, &block)
|
87
|
-
|
90
|
+
return super if File.expand_path(caller.first[/^[^:]+/]) == File.expand_path(__FILE__)
|
91
|
+
proc { |env| new(*args, &block).call(env) }
|
88
92
|
end
|
89
93
|
end
|
90
94
|
end
|
@@ -92,6 +96,7 @@ module AsyncRack
|
|
92
96
|
|
93
97
|
module Mixin
|
94
98
|
extend LateInitializer
|
99
|
+
attr_accessor :env
|
95
100
|
|
96
101
|
def async_callback(result)
|
97
102
|
@async_callback.call result
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rack'
|
2
|
+
module AsyncRack
|
3
|
+
class CatchAsync
|
4
|
+
Rack::CatchAsync = self unless defined? Rack::CatchAsync
|
5
|
+
|
6
|
+
def initialize(app, async_response = [-1, {}, []])
|
7
|
+
@app, @async_response = app, async_response
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
response = @async_response
|
12
|
+
catch(:async) { response = @app.call env }
|
13
|
+
response
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module AsyncRack
|
4
|
+
class ThrowAsync
|
5
|
+
Rack::ThrowAsync = self unless defined? Rack::ThrowAsync
|
6
|
+
|
7
|
+
def initialize(app, throw_on = [-1, 0])
|
8
|
+
@app, @throw_on = app, throw_on
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
response = @app.call env
|
13
|
+
throw :async if @throw_on.include? response.first
|
14
|
+
response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -28,7 +28,6 @@ describe AsyncRack::AsyncCallback do
|
|
28
28
|
before do
|
29
29
|
@class = Class.new do
|
30
30
|
include AsyncRack::AsyncCallback::SimpleWrapper
|
31
|
-
attr_accessor :app, :env
|
32
31
|
class << self
|
33
32
|
attr_accessor :instance
|
34
33
|
end
|
@@ -44,8 +43,7 @@ describe AsyncRack::AsyncCallback do
|
|
44
43
|
end
|
45
44
|
|
46
45
|
it "runs #call again on async callback, replacing app" do
|
47
|
-
middleware = @class.create
|
48
|
-
middleware.app = proc { throw :async }
|
46
|
+
middleware = @class.create proc { throw :async }
|
49
47
|
catch(:async) do
|
50
48
|
middleware.call "async.callback" => proc { |x| x + 10 }
|
51
49
|
raise "should not get here"
|
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 0
|
7
7
|
- 4
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.4.0.
|
9
|
+
- d
|
10
|
+
version: 0.4.0.d
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Konstantin Haase
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-03-
|
18
|
+
date: 2010-03-14 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -57,6 +57,7 @@ extra_rdoc_files: []
|
|
57
57
|
files:
|
58
58
|
- lib/async-rack.rb
|
59
59
|
- lib/async_rack/async_callback.rb
|
60
|
+
- lib/async_rack/catch_async.rb
|
60
61
|
- lib/async_rack/chunked.rb
|
61
62
|
- lib/async_rack/commonlogger.rb
|
62
63
|
- lib/async_rack/conditionalget.rb
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- lib/async_rack/session/memcache.rb
|
74
75
|
- lib/async_rack/session/pool.rb
|
75
76
|
- lib/async_rack/showstatus.rb
|
77
|
+
- lib/async_rack/throw_async.rb
|
76
78
|
- lib/async_rack.rb
|
77
79
|
- spec/async_rack/async_callback_spec.rb
|
78
80
|
- spec/spec_helper.rb
|