resque-kalashnikov 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +99 -0
  7. data/Rakefile +7 -0
  8. data/demo/.gitignore +15 -0
  9. data/demo/Gemfile +31 -0
  10. data/demo/README.rdoc +9 -0
  11. data/demo/Rakefile +7 -0
  12. data/demo/app/assets/images/rails.png +0 -0
  13. data/demo/app/assets/javascripts/application.js +13 -0
  14. data/demo/app/assets/stylesheets/application.css +13 -0
  15. data/demo/app/controllers/application_controller.rb +3 -0
  16. data/demo/app/controllers/test_controller.rb +15 -0
  17. data/demo/app/helpers/application_helper.rb +2 -0
  18. data/demo/app/mailers/.gitkeep +0 -0
  19. data/demo/app/models/.gitkeep +0 -0
  20. data/demo/app/workers/slow_http_request.rb +3 -0
  21. data/demo/config.ru +4 -0
  22. data/demo/config/application.rb +65 -0
  23. data/demo/config/boot.rb +6 -0
  24. data/demo/config/environment.rb +5 -0
  25. data/demo/config/environments/development.rb +26 -0
  26. data/demo/config/environments/production.rb +51 -0
  27. data/demo/config/environments/test.rb +35 -0
  28. data/demo/config/initializers/backtrace_silencers.rb +7 -0
  29. data/demo/config/initializers/inflections.rb +15 -0
  30. data/demo/config/initializers/mime_types.rb +5 -0
  31. data/demo/config/initializers/secret_token.rb +7 -0
  32. data/demo/config/initializers/session_store.rb +8 -0
  33. data/demo/config/initializers/wrap_parameters.rb +10 -0
  34. data/demo/config/locales/en.yml +5 -0
  35. data/demo/config/routes.rb +11 -0
  36. data/demo/db/seeds.rb +7 -0
  37. data/demo/lib/assets/.gitkeep +0 -0
  38. data/demo/lib/tasks/.gitkeep +0 -0
  39. data/demo/log/.gitkeep +0 -0
  40. data/demo/public/404.html +26 -0
  41. data/demo/public/422.html +26 -0
  42. data/demo/public/500.html +25 -0
  43. data/demo/public/favicon.ico +0 -0
  44. data/demo/public/index.html +12 -0
  45. data/demo/public/robots.txt +5 -0
  46. data/demo/script/rails +6 -0
  47. data/demo/script/resque_async.rb +29 -0
  48. data/demo/vendor/assets/javascripts/.gitkeep +0 -0
  49. data/demo/vendor/assets/stylesheets/.gitkeep +0 -0
  50. data/demo/vendor/plugins/.gitkeep +0 -0
  51. data/demo/zeus.json +22 -0
  52. data/lib/event_machine/forced_stop.rb +3 -0
  53. data/lib/resque/catridge.rb +87 -0
  54. data/lib/resque/plugins/resque_kalashnikov/resque_kalashnikov.rb +130 -0
  55. data/lib/resque_kalashnikov.rb +17 -0
  56. data/lib/resque_kalashnikov/delegation.rb +153 -0
  57. data/lib/resque_kalashnikov/http_request.rb +64 -0
  58. data/lib/resque_kalashnikov/railtie.rb +10 -0
  59. data/lib/resque_kalashnikov/server.rb +50 -0
  60. data/lib/resque_kalashnikov/server/views/catridges.erb +57 -0
  61. data/lib/resque_kalashnikov/version.rb +3 -0
  62. data/lib/tasks.rb +34 -0
  63. data/resque-kalashnikov.gemspec +30 -0
  64. data/screenshot.png +0 -0
  65. data/spec/catridge_spec.rb +42 -0
  66. data/spec/http_request_spec.rb +84 -0
  67. data/spec/server_spec.rb +46 -0
  68. data/spec/spec_helper.rb +56 -0
  69. data/spec/support/stub_server.rb +46 -0
  70. data/spec/worker_spec.rb +113 -0
  71. data/tasks/resque_kalashnikov.rake +2 -0
  72. metadata +267 -0
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ResqueKalashnikov::HttpRequest' do
4
+
5
+ def build(attrs={})
6
+ url = attrs.delete('url') || async_server_url
7
+ http_method = attrs.delete('http_method') || 'get'
8
+ ResqueKalashnikov::HttpRequest.new(url, http_method, attrs)
9
+ end
10
+
11
+ def success_response
12
+ { :status => 200, :body => "success", :headers => {} }
13
+ end
14
+
15
+ ['get', 'post', 'delete', 'put'].each do |http_method|
16
+ it "stores valid #{http_method} methods" do
17
+ stub_request(http_method.to_sym, async_server_url).to_return success_response
18
+ EM.synchrony do
19
+ build("http_method" => http_method).send(:http_request).response.should == 'success'
20
+ EM.stop
21
+ end
22
+ end
23
+ end
24
+
25
+ ['head', 'options', 'patch'].each do |http_method|
26
+ it "stores valid #{http_method} methods" do
27
+ stub_request(http_method.to_sym, async_server_url).to_return success_response
28
+ EM.synchrony do
29
+ build("http_method" => http_method).send(:http_request).response.should == ''
30
+ EM.stop
31
+ end
32
+ end
33
+ end
34
+
35
+ it 'stores invalid methods as GET' do
36
+ stub_request(:get, async_server_url).to_return success_response
37
+ EM.synchrony do
38
+ build.send(:http_request).response.should == 'success'
39
+ build('http_method' => 'foobar').send(:http_request).response.should == 'success'
40
+ EM.stop
41
+ end
42
+ end
43
+
44
+ it 'handles misc options' do
45
+ stub_request(:get, async_server_url)
46
+ .with(:query => {"a" => ["b", "c"], "d" => "e"})
47
+ .to_return(success_response)
48
+
49
+ stub_request(:post, "http://127.0.0.1:8081/?d=e&n=1&kind=async")
50
+ .to_return(success_response)
51
+
52
+ EM.synchrony do
53
+ build(
54
+ "a" => ["b", "c"],
55
+ "d" => "e"
56
+ ).send(:http_request).response.should == 'success'
57
+
58
+ build(
59
+ "url" => async_server_url({n: 1, kind: 'async'}),
60
+ "http_method" => "post",
61
+ "d" => "e"
62
+ ).send(:http_request).response.should == 'success'
63
+ EM.stop
64
+ end
65
+ end
66
+
67
+ describe 'error handling' do
68
+ it 'handles 4xx responses' do
69
+ stub_request(:any, async_server_url).to_return(:status => [404, "Not Found"])
70
+ EM.synchrony do
71
+ build.send(:http_request).response_header.status.should == 404
72
+ EM.stop
73
+ end
74
+ end
75
+
76
+ it 'handles 5xx responses' do
77
+ stub_request(:any, async_server_url).to_return(:status => [500, "Internal Server Error"])
78
+ EM.synchrony do
79
+ build.send(:http_request).response_header.status.should == 500
80
+ EM.stop
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require "resque_kalashnikov/server"
3
+
4
+ ENV['RACK_ENV'] = 'test'
5
+
6
+ describe ResqueKalashnikov::Server do
7
+ require 'rack/test'
8
+ include Rack::Test::Methods
9
+
10
+ def app
11
+ Resque::Server
12
+ end
13
+
14
+ it 'has Kalashnikov tab' do
15
+ get '/overview'
16
+ last_response.body.should =~ /kalashnikov/
17
+ end
18
+
19
+ it 'can show Kalashnikov tab' do
20
+ get '/kalashnikov'
21
+ last_response.status.should == 200
22
+ end
23
+
24
+ describe 'actions' do
25
+ before do
26
+ @request_key = Base64.encode64 Resque.encode [SlowHttpRequest, [async_server_url, {method: 'post'}]]
27
+ @fake_redis = double
28
+ Redis.stub(:connect).and_return(@fake_redis)
29
+ end
30
+
31
+ it 'can retry jobs' do
32
+ @fake_redis.should_receive(:rpush).once
33
+ post '/kalashnikov/retry/500', {request_key: @request_key}
34
+ end
35
+
36
+ it 'can reset misfire count' do
37
+ @fake_redis.should_receive(:rpush).once
38
+ post '/kalashnikov/retry/500', {request_key: @request_key}
39
+ end
40
+
41
+ it 'can reset everyhing' do
42
+ Resque::Catridge.should_receive(:reset_stats)
43
+ get '/kalashnikov/reset_stats'
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'resque'
3
+ require 'em-synchrony'
4
+ require 'em-synchrony/em-hiredis'
5
+ require 'webmock/rspec'
6
+
7
+ $dir = File.dirname(File.expand_path(__FILE__))
8
+ $LOAD_PATH.unshift $dir + '/../lib'
9
+ require 'resque_kalashnikov'
10
+ require 'support/stub_server'
11
+ $TESTING = true
12
+
13
+ RSpec.configure do |config|
14
+ config.treat_symbols_as_metadata_keys_with_true_values = true
15
+ config.run_all_when_everything_filtered = true
16
+ config.filter_run :focus
17
+ config.order = 'random'
18
+
19
+ config.before do
20
+ Redis.connect.flushall
21
+ end
22
+ end
23
+
24
+ class SlowHttpRequest < ResqueKalashnikov::HttpRequest
25
+ @queue = :async_queue
26
+
27
+ def handle http
28
+ super
29
+ File.open("/tmp/kalashnikov-#{$$}.log", "a") do |f|
30
+ f.write "#{DateTime.now}:#{http.response_header.status}:#{http.response}\n"
31
+ end
32
+ end
33
+ end
34
+
35
+ def async_server(response_status=200, delay=0)
36
+ WebMock.allow_net_connect!
37
+ EM.synchrony do
38
+ #EM::HttpRequest.new('http://httplogger.herokuapp.com/bvlog/clear').get if async_server_url['herokuapp']
39
+ Resque.redis = EM::Synchrony::ConnectionPool.new(size: 3) do
40
+ EM::Hiredis.connect
41
+ end
42
+ #Resque.redis.flushall # reset state in Resque object
43
+ s = StubServer.new response_status, delay
44
+ yield
45
+ s.stop
46
+ end
47
+ end
48
+
49
+ def async_server_url(attrs={})
50
+ #return "http://httplogger.herokuapp.com/bvlog/get"
51
+ if attrs.empty?
52
+ "http://127.0.0.1:8081"
53
+ else
54
+ "http://127.0.0.1:8081/?n=#{attrs[:n]}&kind=#{attrs[:kind]}"
55
+ end
56
+ end
@@ -0,0 +1,46 @@
1
+ require 'eventmachine'
2
+
3
+ # thanks @igrigorik
4
+ # https://github.com/igrigorik/em-synchrony/blob/master/spec/helper/stub-http-server.rb
5
+ class StubServer
6
+ module Server
7
+ attr_accessor :responses, :delay
8
+ def receive_data(data)
9
+ EM.add_timer(@delay) {
10
+ send_data @responses.sample
11
+ close_connection_after_writing
12
+ }
13
+ end
14
+ end
15
+
16
+ def initialize(response_code=[200], delay=0, port=8081)
17
+ @sig = EventMachine::start_server("127.0.0.1", port, Server) { |s|
18
+ response_map = {
19
+ "500" => "HTTP/1.0 500 Internal Server Error\r\nConnection: close\r\n\r\nFail: 500",
20
+ "404" => "HTTP/1.0 404 Not Found\r\nConnection: close\r\n\r\nNot Found: 404",
21
+ "200" => "HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nSuccess",
22
+ }
23
+ s.responses = response_map.select { |k,v| response_code.to_s.include? k } .values
24
+ s.delay = delay
25
+ }
26
+ end
27
+
28
+ def stop
29
+ EventMachine.stop_server @sig
30
+ end
31
+ end
32
+
33
+ if __FILE__ == $0
34
+ EM.run do
35
+ s = StubServer.new(ARGV || [200], 0)
36
+ puts 'Started on http://localhost:8081/'
37
+
38
+ ['TERM', 'INT', 'QUIT'].each do |signal|
39
+ trap(signal) do
40
+ puts 'Finished'
41
+ s.stop
42
+ EM.stop
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ DELAY = 0.5
4
+
5
+ describe 'Resque::Worker' do
6
+ before do
7
+ Resque.before_first_fork = nil
8
+ Resque.before_fork = nil
9
+ Resque.after_fork = nil
10
+ @worker = Resque::Worker.new(:async_queue, :sync_queue)
11
+ #@worker.verbose = true # useful to see sync/async difference
12
+ end
13
+
14
+ def now(); Time.now.to_f; end
15
+
16
+ def create_async_job(attrs={})
17
+ attrs.merge! kind: 'async'
18
+ Resque::Job.create(:async_queue, SlowHttpRequest, async_server_url(attrs), attrs)
19
+ end
20
+
21
+ def create_sync_job(attrs={})
22
+ attrs.merge! kind: 'sync'
23
+ Resque::Job.create(:sync_queue, SlowHttpRequest, async_server_url(attrs), attrs)
24
+ end
25
+
26
+ it 'has proper name' do
27
+ @worker.inspect.should =~ /KalashnikovWorker/
28
+ end
29
+
30
+ it 'makes acquires jobs with Hiredis#blpop' do
31
+ create_sync_job
32
+ @worker.reserve.should be_kind_of Resque::Job
33
+ end
34
+
35
+ it 'differs async jobs' do
36
+ create_async_job
37
+ @worker.can_do_job_async?(Resque::Job.reserve :async_queue).should be_true
38
+ end
39
+
40
+ it 'differs sync jobs' do
41
+ create_sync_job
42
+ @worker.can_do_job_async?(Resque::Job.reserve :sync_queue).should be_false
43
+ end
44
+
45
+ it 'handles async queues with fibers' do
46
+ queue_size = 20
47
+ queue_size.times { |n| create_async_job(n: n) }
48
+
49
+ async_server([200], DELAY) do
50
+ start = now
51
+ @worker.work(0) do |job|
52
+ # block yields in Worker#perform in "ensure" part
53
+ #
54
+ # this is too early - Fiber hasn't finished till this moment
55
+ # if theirs count is small, it's still ok
56
+ #
57
+ # if there were 100 jobs - they'll have managed ~60
58
+ # but uncommenting "if" statement leads to ever-hook in EM
59
+ # having ~30 alive fibers after having done 100 jobs
60
+ #
61
+ # TLDR: kalashnikov-worker is hard to stop with block - use signals
62
+ @worker.shutdown #if Resque.size(:async_queue) == 0
63
+ end
64
+
65
+ # O(1)
66
+ (now - start).should be_within(DELAY*2).of(DELAY)
67
+ end
68
+ end
69
+
70
+ it 'handles sync queues with processes' do
71
+ queue_size = 3
72
+ queue_size.times { |n| create_sync_job(n: n) }
73
+
74
+ async_server([200], DELAY) do
75
+ start = now
76
+ @worker.work(0) do |job|
77
+ @worker.shutdown if Resque.size(:sync_queue) == 0
78
+ end
79
+
80
+ # O(n)
81
+ (now - start).should be_within(DELAY*queue_size*2).of(DELAY*queue_size)
82
+ end
83
+ end
84
+
85
+ it 'handles 404 & 500 error async' do
86
+ queue_size = 20
87
+ queue_size.times { |n| create_async_job(n: n) }
88
+ async_server([500, 404], DELAY) do
89
+ start = now
90
+ @worker.work(0) do |job|
91
+ @worker.shutdown #if Resque.size(:async_queue) == 0
92
+ end
93
+
94
+ # O(1)
95
+ (now - start).should be_within(DELAY*2).of(DELAY)
96
+ end
97
+ end
98
+
99
+ it 'handles random async jobs' do
100
+ queue_size = 20
101
+ queue_size.times { |n| create_async_job(n: n) }
102
+
103
+ async_server([200, 404, 500], DELAY) do
104
+ start = now
105
+ @worker.work(0) do |job|
106
+ @worker.shutdown #if Resque.size(:async_queue) == 0
107
+ end
108
+
109
+ # O(1)
110
+ (now - start).should be_within(DELAY*2).of(DELAY)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'resque_kalashnikov/tasks'
metadata ADDED
@@ -0,0 +1,267 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-kalashnikov
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vlad Bokov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: resque
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.23.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.23.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: redis
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>'
52
+ - !ruby/object:Gem::Version
53
+ version: 3.0.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>'
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: em-http-request
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: em-synchrony
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: em-hiredis
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rack-test
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: webmock
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rspec
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ description: Handles your HTTP requests in background in non-blocking way using Resque
159
+ worker
160
+ email:
161
+ - bokov.vlad@gmail.com
162
+ executables: []
163
+ extensions: []
164
+ extra_rdoc_files: []
165
+ files:
166
+ - .gitignore
167
+ - .rspec
168
+ - .travis.yml
169
+ - Gemfile
170
+ - LICENSE.txt
171
+ - README.md
172
+ - Rakefile
173
+ - demo/.gitignore
174
+ - demo/Gemfile
175
+ - demo/README.rdoc
176
+ - demo/Rakefile
177
+ - demo/app/assets/images/rails.png
178
+ - demo/app/assets/javascripts/application.js
179
+ - demo/app/assets/stylesheets/application.css
180
+ - demo/app/controllers/application_controller.rb
181
+ - demo/app/controllers/test_controller.rb
182
+ - demo/app/helpers/application_helper.rb
183
+ - demo/app/mailers/.gitkeep
184
+ - demo/app/models/.gitkeep
185
+ - demo/app/workers/slow_http_request.rb
186
+ - demo/config.ru
187
+ - demo/config/application.rb
188
+ - demo/config/boot.rb
189
+ - demo/config/environment.rb
190
+ - demo/config/environments/development.rb
191
+ - demo/config/environments/production.rb
192
+ - demo/config/environments/test.rb
193
+ - demo/config/initializers/backtrace_silencers.rb
194
+ - demo/config/initializers/inflections.rb
195
+ - demo/config/initializers/mime_types.rb
196
+ - demo/config/initializers/secret_token.rb
197
+ - demo/config/initializers/session_store.rb
198
+ - demo/config/initializers/wrap_parameters.rb
199
+ - demo/config/locales/en.yml
200
+ - demo/config/routes.rb
201
+ - demo/db/seeds.rb
202
+ - demo/lib/assets/.gitkeep
203
+ - demo/lib/tasks/.gitkeep
204
+ - demo/log/.gitkeep
205
+ - demo/public/404.html
206
+ - demo/public/422.html
207
+ - demo/public/500.html
208
+ - demo/public/favicon.ico
209
+ - demo/public/index.html
210
+ - demo/public/robots.txt
211
+ - demo/script/rails
212
+ - demo/script/resque_async.rb
213
+ - demo/vendor/assets/javascripts/.gitkeep
214
+ - demo/vendor/assets/stylesheets/.gitkeep
215
+ - demo/vendor/plugins/.gitkeep
216
+ - demo/zeus.json
217
+ - lib/event_machine/forced_stop.rb
218
+ - lib/resque/catridge.rb
219
+ - lib/resque/plugins/resque_kalashnikov/resque_kalashnikov.rb
220
+ - lib/resque_kalashnikov.rb
221
+ - lib/resque_kalashnikov/delegation.rb
222
+ - lib/resque_kalashnikov/http_request.rb
223
+ - lib/resque_kalashnikov/railtie.rb
224
+ - lib/resque_kalashnikov/server.rb
225
+ - lib/resque_kalashnikov/server/views/catridges.erb
226
+ - lib/resque_kalashnikov/version.rb
227
+ - lib/tasks.rb
228
+ - resque-kalashnikov.gemspec
229
+ - screenshot.png
230
+ - spec/catridge_spec.rb
231
+ - spec/http_request_spec.rb
232
+ - spec/server_spec.rb
233
+ - spec/spec_helper.rb
234
+ - spec/support/stub_server.rb
235
+ - spec/worker_spec.rb
236
+ - tasks/resque_kalashnikov.rake
237
+ homepage: ''
238
+ licenses: []
239
+ post_install_message:
240
+ rdoc_options: []
241
+ require_paths:
242
+ - lib
243
+ required_ruby_version: !ruby/object:Gem::Requirement
244
+ none: false
245
+ requirements:
246
+ - - ! '>='
247
+ - !ruby/object:Gem::Version
248
+ version: '0'
249
+ required_rubygems_version: !ruby/object:Gem::Requirement
250
+ none: false
251
+ requirements:
252
+ - - ! '>='
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
255
+ requirements: []
256
+ rubyforge_project:
257
+ rubygems_version: 1.8.24
258
+ signing_key:
259
+ specification_version: 3
260
+ summary: This is awesome
261
+ test_files:
262
+ - spec/catridge_spec.rb
263
+ - spec/http_request_spec.rb
264
+ - spec/server_spec.rb
265
+ - spec/spec_helper.rb
266
+ - spec/support/stub_server.rb
267
+ - spec/worker_spec.rb