rack-fiber_pool 0.9.3 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODZjMmFjMWUyNjYyMDQ4NzFkYzE4ZGQ3NDRmOWMzYzNiMTBhMWQ3ZQ==
5
+ data.tar.gz: !binary |-
6
+ ZWFiODk4Mzc2Y2RkNmIzODk4NGRjYTEwNmZmMTA5ODAyMmY2ZDM2YQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OTIxYWI1NjRkODY3MTQxNTU5OWZjYmFlZWQwY2Q0NDI1YmVjMDdjZGZmMTc5
10
+ N2I3YzUwNmFlZGM3MjMwNmI0NWNkOWM3ZWFhYmJlZGI0MmJkZWUyMDEyOGRl
11
+ NzkzZWI5MzY2NzRmZTNhZmYwNzUxYTczOWU5N2ZiYWMyMjk3M2Y=
12
+ data.tar.gz: !binary |-
13
+ ZDNiYzRjODMwM2U5YmM4YTY5OTFhYTYyOGZmYjBjZWUyNmNlYWRjYWU0OGRh
14
+ MjQ2NmJkMWQ3ZjFhY2IyZWVlODY1OTk1YWVhZDkyYmIzZDVjOWYxMmIxODFl
15
+ NGM3NmFlODY3YzM5ZDgwNWYxODdiOWI2MjAzODRkZTZlYmFiMzg=
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ coverage
2
+ Gemfile.lock
3
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'coveralls'
data/Guardfile ADDED
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ guard 'rspec' do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
9
+ guard 'rubocop' do
10
+ watch(%r{.+\.rb$})
11
+ #watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
12
+ end
13
+
14
+ guard 'bundler' do
15
+ watch('Gemfile')
16
+ watch(/^.+\.gemspec/)
17
+ end
data/README.md CHANGED
@@ -1,5 +1,3 @@
1
- The new homepage is
2
- [https://github.com/alebsack/rack-fiber_pool](https://github.com/alebsack/rack-fiber_pool)
3
1
 
4
2
  rack-fiber_pool
5
3
  ---------------
data/Rakefile CHANGED
@@ -1,8 +1,10 @@
1
- require 'rake/testtask'
2
- Rake::TestTask.new(:test) do |test|
3
- test.libs << 'test'
4
- test.pattern = 'test/**/test_*.rb'
5
- test.verbose = true
6
- end
1
+ require "bundler/gem_tasks"
7
2
 
8
- task :default => :test
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+
6
+ task :default => [:spec]
7
+ task :test => [:spec]
8
+
9
+ desc "Run all RSpec tests"
10
+ RSpec::Core::RakeTask.new(:spec)
data/example/app.rb CHANGED
@@ -1,4 +1,6 @@
1
- raise LoadError, "Ruby 1.9.1 only" if RUBY_VERSION < '1.9.1'
1
+ # encoding: utf-8
2
+
3
+ fail LoadError, 'Ruby 1.9.1 only' if RUBY_VERSION < '1.9.1'
2
4
 
3
5
  require 'sinatra/base'
4
6
  require 'fiber'
@@ -10,14 +12,12 @@ require 'rack/fiber_pool'
10
12
  # rackup -s thin app.rb
11
13
  # http://localhost:9292/test
12
14
  class App < Sinatra::Base
13
-
14
15
  use Rack::FiberPool
15
16
 
16
17
  set :root, File.dirname(__FILE__)
17
18
 
18
19
  get '/test' do
19
- content_type "text/plain"
20
+ content_type 'text/plain'
20
21
  body "Hello world from #{Fiber.current}"
21
22
  end
22
-
23
- end
23
+ end
@@ -1,33 +1,53 @@
1
- require 'fiber_pool'
1
+ # encoding: utf-8
2
2
 
3
3
  module Rack
4
+ # Rack::FiberPool is a Rack Middleware which runs each request in its own
5
+ # fiber. Fibers are reused for each request. This middleware is suitable
6
+ # for Thin servers.
4
7
  class FiberPool
5
- VERSION = '0.9.3'
8
+ VERSION = '1.0.0.beta.1'
6
9
  SIZE = 100
7
10
 
8
- # The size of the pool is configurable:
9
- #
10
- # use Rack::FiberPool, :size => 25
11
- def initialize(app, options={})
11
+ # Initializer for Rack::FiberPool
12
+ # @param [Hash] opts the options to configure the fiber pool
13
+ # @option opts [Fixnum] :size Size of the fiber pool (concurrent requests)
14
+ # @option opts [String] :rescue_exception your custom exception handler
15
+ def initialize(app, options = {})
12
16
  @app = app
13
- @fiber_pool = ::FiberPool.new(options[:size] || SIZE)
14
- @rescue_exception = options[:rescue_exception] || Proc.new { |env, e| [500, {}, ["#{e.class.name}: #{e.message.to_s}"]] }
17
+ @fibers = []
18
+ @count = options[:size] || SIZE
19
+ @count.times do
20
+ @fibers << Fiber.new { |block| loop { block = fiber_loop(block) } }
21
+ end
22
+ @rescue_exception = options[:rescue_exception] || proc do |env, e|
23
+ [500, {}, ["#{e.class.name}: #{e.message.to_s}"]]
24
+ end
15
25
  yield @fiber_pool if block_given?
16
26
  end
17
27
 
18
- def call(env)
19
- call_app = lambda do
20
- env['async.orig_callback'] = env.delete('async.callback')
21
- begin
22
- result = @app.call(env)
23
- env['async.orig_callback'].call result
24
- rescue ::Exception => e
25
- env['async.orig_callback'].call @rescue_exception.call(env, e)
26
- end
27
- end
28
-
29
- @fiber_pool.spawn(&call_app)
28
+ def call(parent_env)
29
+ env = parent_env.dup
30
+ fail 'Server is at capacity' unless (fiber = @fibers.shift)
31
+ fiber.resume ->{ request(env) }
30
32
  throw :async
33
+ rescue => exception
34
+ [503, {}, [exception.message]]
35
+ end
36
+
37
+ private
38
+
39
+ def request(env)
40
+ env['async.orig_callback'] = env.delete('async.callback')
41
+ result = @app.call(env)
42
+ env['async.orig_callback'].call result
43
+ rescue Exception => exc
44
+ env['async.orig_callback'].call @rescue_exception.call(env, exc)
45
+ end
46
+
47
+ def fiber_loop(block)
48
+ block.call
49
+ @fibers.unshift Fiber.current
50
+ Fiber.yield
31
51
  end
32
52
  end
33
53
  end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "rack-fiber_pool"
5
+ spec.version = '1.0.0.beta.1'
6
+ spec.authors = ["Mike Perham", 'Adam Lebsack']
7
+ spec.date = Time.now.utc.strftime("%Y-%m-%d")
8
+ spec.email = %w(mperham@gmail.com alebsack@gmail.com)
9
+ spec.homepage = "http://github.com/alebsack/rack-fiber_pool"
10
+ spec.rdoc_options = ["--charset=UTF-8"]
11
+ spec.require_paths = ["lib"]
12
+ spec.summary = spec.description = "Rack middleware to run each request within a Fiber"
13
+
14
+ spec.files = `git ls-files`.split("\n")
15
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_runtime_dependency 'rack'
20
+ spec.add_runtime_dependency 'fiberpool'
21
+
22
+ spec.add_development_dependency 'thin', '~> 1.6.1'
23
+ spec.add_development_dependency 'em-synchrony'
24
+ spec.add_development_dependency 'em-http-request'
25
+ spec.add_development_dependency 'sinatra'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rspec'
28
+ spec.add_development_dependency 'guard'
29
+ spec.add_development_dependency 'guard-rspec'
30
+ spec.add_development_dependency 'guard-bundler'
31
+ spec.add_development_dependency 'guard-rubocop'
32
+ spec.add_development_dependency 'rubocop'
33
+ spec.add_development_dependency 'spork'
34
+ spec.add_development_dependency 'simplecov'
35
+ end
36
+
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'rack/fiber_pool'
5
+
6
+ def make_request(url)
7
+ f = Fiber.current
8
+ Fiber.new do
9
+ http = EventMachine::HttpRequest.new(url).get
10
+ http.errback { |r| f.resume(r) }
11
+ http.callback { f.resume(http) }
12
+ end.resume
13
+ Fiber.yield
14
+ end
15
+
16
+ require 'sinatra'
17
+ class RecursionApp < Sinatra::Base
18
+ use Rack::FiberPool
19
+
20
+ set :show_exceptions, false
21
+ set :raise_errors, true
22
+
23
+ get '/:id' do
24
+ halt 404 unless (id = params[:id].to_i)
25
+ halt 404 if id == 0
26
+
27
+ r = make_request("#{settings.loop_url}/#{id - 1}")
28
+ fail r.error if r.error
29
+
30
+ content_type 'text/plain'
31
+ if r.response_header.status == 200
32
+ body r.response
33
+ status 200
34
+ elsif r.response_header.status == 404
35
+ body "ID #{id} not found"
36
+ status 404
37
+ else
38
+ body r.response
39
+ status r.response_header.status
40
+ end
41
+ end
42
+ end
43
+
44
+ describe 'recursion scenario' do
45
+ let(:thin_app) { RecursionApp }
46
+ let(:thin_url) { "http://#{thin_address}:#{thin_port}" }
47
+ before { RecursionApp.set :loop_url, thin_url }
48
+
49
+ include_context 'thin server'
50
+
51
+ it 'should hit the fiber pool limit' do
52
+ r = make_request "#{thin_url}/100"
53
+ r.response_header.status.should eq 503
54
+ r.response.should eq 'Server is at capacity'
55
+ end
56
+
57
+ it 'should hit the fiber pool limit twice' do
58
+ r = make_request "#{thin_url}/100"
59
+ r.response_header.status.should eq 503
60
+ r.response.should eq 'Server is at capacity'
61
+
62
+ r = make_request "#{thin_url}/100"
63
+ r.response_header.status.should eq 503
64
+ r.response.should eq 'Server is at capacity'
65
+ end
66
+
67
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'rack/fiber_pool'
6
+
7
+ describe Rack::FiberPool do
8
+ class TestBuggyApp
9
+ attr_accessor :result
10
+ def call(env)
11
+ env['async.orig_callback'] = proc { |result| @result = result }
12
+ fail Exception, 'I\'m buggy! Please fix me.'
13
+ end
14
+ end
15
+
16
+ class TestApp
17
+ attr_accessor :result
18
+ def call(env)
19
+ env['async.orig_callback'] = proc { |result| @result = result }
20
+ [200, { 'Content-Type' => 'text/plain' }, ['Hello world!']]
21
+ end
22
+ end
23
+
24
+ subject { app.result }
25
+ let(:options) { {} }
26
+ before do
27
+ catch :async do
28
+ Rack::MockRequest.new(Rack::FiberPool.new(app, options)).get('/')
29
+ end
30
+ end
31
+
32
+ describe 'usage' do
33
+ let(:app) { TestApp.new }
34
+ it { should eql [200, { 'Content-Type' => 'text/plain' }, ['Hello world!']] }
35
+ end
36
+
37
+ describe 'size' do
38
+ let(:app) { TestApp.new }
39
+ let(:options) { { size: 5 } }
40
+ it { should eql [200, { 'Content-Type' => 'text/plain' }, ['Hello world!']] }
41
+ end
42
+
43
+ describe 'exception' do
44
+ let(:app) { TestBuggyApp.new }
45
+ it { should eql [500, {}, ['Exception: I\'m buggy! Please fix me.']] }
46
+ end
47
+
48
+ describe 'custom rescue exception' do
49
+ let(:app) { TestBuggyApp.new }
50
+ let(:rescue_exception) do
51
+ proc { |env, exception| [503, {}, [exception.message]] }
52
+ end
53
+ let(:options) { { rescue_exception: rescue_exception } }
54
+ it { should eql [503, {}, ['I\'m buggy! Please fix me.']] }
55
+ end
56
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rubygems'
4
+ require 'spork'
5
+ # uncomment the following line to use spork with the debugger
6
+ # require 'spork/ext/ruby-debug'
7
+
8
+ Spork.prefork do
9
+ # Loading more in this block will cause your tests to run faster. However,
10
+ # if you change any configuration or code from libraries loaded here, you'll
11
+ # need to restart spork for it take effect.
12
+
13
+ require 'rspec'
14
+ require 'simplecov'
15
+ require 'coveralls'
16
+
17
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
18
+ SimpleCov::Formatter::HTMLFormatter,
19
+ Coveralls::SimpleCov::Formatter
20
+ ]
21
+ SimpleCov.start do
22
+ add_group 'Lib', 'lib'
23
+ add_filter '/spec/'
24
+ end
25
+
26
+ require 'rack'
27
+ require 'rack/mock'
28
+
29
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
30
+
31
+ RSpec.configure do |config|
32
+ config.treat_symbols_as_metadata_keys_with_true_values = true
33
+ config.run_all_when_everything_filtered = true
34
+ config.filter_run :focus
35
+
36
+ # Run specs in random order to surface order dependencies. If you find an
37
+ # order dependency and want to debug it, you can fix the order by providing
38
+ # the seed, which is printed after each run.
39
+ # --seed 1234
40
+ config.order = 'random'
41
+ end
42
+
43
+ end
44
+
45
+ Spork.each_run do
46
+ # This code will be run each time you run your specs.
47
+
48
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ shared_context 'thin server' do
4
+ before(:all) do
5
+ require 'thin'
6
+ require 'em-synchrony'
7
+ require 'sinatra'
8
+ require 'em-http-request'
9
+ end
10
+
11
+ let(:thin_address) { '127.0.0.1' }
12
+ let(:thin_port) { ENV['PORT'] || 42_678 }
13
+ around(:each) do |example|
14
+ require 'em-synchrony'
15
+ EventMachine.error_handler do |e|
16
+ puts "Error in Eventmachine: #{e.inspect}"
17
+ puts e.backtrace.join("\n")
18
+ EventMachine.stop
19
+ end
20
+ EventMachine.synchrony do
21
+ options = { signals: false }
22
+ Thin::Logging.silent = true
23
+ server = Thin::Server.new(thin_address, thin_port, options)
24
+ server.maximum_connections = 1024
25
+ server.app = thin_app
26
+ server.start!
27
+ example.run
28
+ server.stop
29
+ EventMachine.stop
30
+ end
31
+ end
32
+ end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-fiber_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
5
- prerelease:
4
+ version: 1.0.0.beta.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Mike Perham
@@ -10,8 +9,218 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-03-19 00:00:00.000000000 Z
14
- dependencies: []
12
+ date: 2013-11-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: fiberpool
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: thin
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 1.6.1
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 1.6.1
56
+ - !ruby/object:Gem::Dependency
57
+ name: em-synchrony
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: em-http-request
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: sinatra
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: guard
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: guard-rspec
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: guard-bundler
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: guard-rubocop
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: rubocop
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ! '>='
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ - !ruby/object:Gem::Dependency
197
+ name: spork
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ! '>='
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ! '>='
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ - !ruby/object:Gem::Dependency
211
+ name: simplecov
212
+ requirement: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ! '>='
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ type: :development
218
+ prerelease: false
219
+ version_requirements: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ! '>='
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
15
224
  description: Rack middleware to run each request within a Fiber
16
225
  email:
17
226
  - mperham@gmail.com
@@ -20,39 +229,46 @@ executables: []
20
229
  extensions: []
21
230
  extra_rdoc_files: []
22
231
  files:
232
+ - .gitignore
233
+ - Gemfile
234
+ - Guardfile
23
235
  - LICENSE
24
236
  - README.md
25
237
  - Rakefile
26
238
  - example/app.rb
27
- - lib/fiber_pool.rb
28
239
  - lib/rack/fiber_pool.rb
29
- - test/helper.rb
30
- - test/test_rack-fiber_pool.rb
240
+ - rack-fiber_pool.gemspec
241
+ - spec/integration/recursion_spec.rb
242
+ - spec/lib/fiber_pool/fiber_pool_spec.rb
243
+ - spec/spec_helper.rb
244
+ - spec/support/thin.rb
31
245
  homepage: http://github.com/alebsack/rack-fiber_pool
32
246
  licenses: []
247
+ metadata: {}
33
248
  post_install_message:
34
249
  rdoc_options:
35
250
  - --charset=UTF-8
36
251
  require_paths:
37
252
  - lib
38
253
  required_ruby_version: !ruby/object:Gem::Requirement
39
- none: false
40
254
  requirements:
41
255
  - - ! '>='
42
256
  - !ruby/object:Gem::Version
43
257
  version: '0'
44
258
  required_rubygems_version: !ruby/object:Gem::Requirement
45
- none: false
46
259
  requirements:
47
- - - ! '>='
260
+ - - ! '>'
48
261
  - !ruby/object:Gem::Version
49
- version: '0'
262
+ version: 1.3.1
50
263
  requirements: []
51
264
  rubyforge_project:
52
- rubygems_version: 1.8.25
265
+ rubygems_version: 2.1.7
53
266
  signing_key:
54
- specification_version: 3
267
+ specification_version: 4
55
268
  summary: Rack middleware to run each request within a Fiber
56
269
  test_files:
57
- - test/helper.rb
58
- - test/test_rack-fiber_pool.rb
270
+ - spec/integration/recursion_spec.rb
271
+ - spec/lib/fiber_pool/fiber_pool_spec.rb
272
+ - spec/spec_helper.rb
273
+ - spec/support/thin.rb
274
+ has_rdoc:
data/lib/fiber_pool.rb DELETED
@@ -1,82 +0,0 @@
1
- # Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
2
- # Copyright:: Copyright (c) 2008 eSpace, Inc.
3
- # License:: Distributes under the same terms as Ruby
4
-
5
- require 'fiber'
6
-
7
- class Fiber
8
-
9
- #Attribute Reference--Returns the value of a fiber-local variable, using
10
- #either a symbol or a string name. If the specified variable does not exist,
11
- #returns nil.
12
- def [](key)
13
- local_fiber_variables[key]
14
- end
15
-
16
- #Attribute Assignment--Sets or creates the value of a fiber-local variable,
17
- #using either a symbol or a string. See also Fiber#[].
18
- def []=(key,value)
19
- local_fiber_variables[key] = value
20
- end
21
-
22
- private
23
-
24
- def local_fiber_variables
25
- @local_fiber_variables ||= {}
26
- end
27
- end
28
-
29
- class FiberPool
30
-
31
- # gives access to the currently free fibers
32
- attr_reader :fibers
33
- attr_reader :busy_fibers
34
-
35
- # Code can register a proc with this FiberPool to be called
36
- # every time a Fiber is finished. Good for releasing resources
37
- # like ActiveRecord database connections.
38
- attr_accessor :generic_callbacks
39
-
40
- # Prepare a list of fibers that are able to run different blocks of code
41
- # every time. Once a fiber is done with its block, it attempts to fetch
42
- # another one from the queue
43
- def initialize(count = 100)
44
- @fibers,@busy_fibers,@queue,@generic_callbacks = [],{},[],[]
45
- count.times do |i|
46
- fiber = Fiber.new do |block|
47
- loop do
48
- block.call
49
- # callbacks are called in a reverse order, much like c++ destructor
50
- Fiber.current[:callbacks].pop.call while Fiber.current[:callbacks].length > 0
51
- generic_callbacks.each do |cb|
52
- cb.call
53
- end
54
- unless @queue.empty?
55
- block = @queue.shift
56
- else
57
- @busy_fibers.delete(Fiber.current.object_id)
58
- @fibers.unshift Fiber.current
59
- block = Fiber.yield
60
- end
61
- end
62
- end
63
- fiber[:callbacks] = []
64
- fiber[:em_keys] = []
65
- @fibers << fiber
66
- end
67
- end
68
-
69
- # If there is an available fiber use it, otherwise, leave it to linger
70
- # in a queue
71
- def spawn(&block)
72
- if fiber = @fibers.shift
73
- fiber[:callbacks] = []
74
- @busy_fibers[fiber.object_id] = fiber
75
- fiber.resume(block)
76
- else
77
- @queue << block
78
- end
79
- self # we are keen on hiding our queue
80
- end
81
-
82
- end
data/test/helper.rb DELETED
@@ -1,4 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack'
3
- require 'rack/mock'
4
- require 'rack/fiber_pool'
@@ -1,53 +0,0 @@
1
- require 'helper'
2
-
3
- class TestRackFiberPool < MiniTest::Unit::TestCase
4
-
5
- def test_usage
6
- app = TestApp.new
7
- catch :async do
8
- res = Rack::MockRequest.new(Rack::FiberPool.new(app)).get("/")
9
- end
10
- assert_equal [200, {"Content-Type"=>"text/plain"}, ["Hello world!"]], app.result
11
- end
12
-
13
- def test_size
14
- app = TestApp.new
15
- catch :async do
16
- res = Rack::MockRequest.new(Rack::FiberPool.new(app, :size => 5)).get("/")
17
- end
18
- assert_equal [200, {"Content-Type"=>"text/plain"}, ["Hello world!"]], app.result
19
- end
20
-
21
- def test_exception
22
- app = TestBuggyApp.new
23
- catch :async do
24
- res = Rack::MockRequest.new(Rack::FiberPool.new(app)).get("/")
25
- end
26
- assert_equal [500, {}, ["Exception: I'm buggy! Please fix me."]], app.result
27
- end
28
-
29
- def test_custom_rescue_exception
30
- app = TestBuggyApp.new
31
- catch :async do
32
- rescue_exception = Proc.new { |env, exception| [503, {}, [exception.message]] }
33
- res = Rack::MockRequest.new(Rack::FiberPool.new(app, :rescue_exception => rescue_exception)).get('/')
34
- end
35
- assert_equal [503, {}, ["I'm buggy! Please fix me."]], app.result
36
- end
37
-
38
- class TestBuggyApp
39
- attr_accessor :result
40
- def call(env)
41
- env['async.orig_callback'] = proc { |result| @result = result }
42
- raise Exception.new("I'm buggy! Please fix me.")
43
- end
44
- end
45
-
46
- class TestApp
47
- attr_accessor :result
48
- def call(env)
49
- env['async.orig_callback'] = proc { |result| @result = result }
50
- [200, {"Content-Type" => "text/plain"}, ["Hello world!"]]
51
- end
52
- end
53
- end