roundhouse-x 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +16 -0
- data/3.0-Upgrade.md +70 -0
- data/Changes.md +1127 -0
- data/Gemfile +27 -0
- data/LICENSE +7 -0
- data/README.md +52 -0
- data/Rakefile +9 -0
- data/bin/roundhouse +19 -0
- data/bin/roundhousectl +93 -0
- data/lib/generators/roundhouse/templates/worker.rb.erb +9 -0
- data/lib/generators/roundhouse/templates/worker_spec.rb.erb +6 -0
- data/lib/generators/roundhouse/templates/worker_test.rb.erb +8 -0
- data/lib/generators/roundhouse/worker_generator.rb +49 -0
- data/lib/roundhouse/actor.rb +39 -0
- data/lib/roundhouse/api.rb +859 -0
- data/lib/roundhouse/cli.rb +396 -0
- data/lib/roundhouse/client.rb +210 -0
- data/lib/roundhouse/core_ext.rb +105 -0
- data/lib/roundhouse/exception_handler.rb +30 -0
- data/lib/roundhouse/fetch.rb +154 -0
- data/lib/roundhouse/launcher.rb +98 -0
- data/lib/roundhouse/logging.rb +104 -0
- data/lib/roundhouse/manager.rb +236 -0
- data/lib/roundhouse/middleware/chain.rb +149 -0
- data/lib/roundhouse/middleware/i18n.rb +41 -0
- data/lib/roundhouse/middleware/server/active_record.rb +13 -0
- data/lib/roundhouse/middleware/server/logging.rb +40 -0
- data/lib/roundhouse/middleware/server/retry_jobs.rb +206 -0
- data/lib/roundhouse/monitor.rb +124 -0
- data/lib/roundhouse/paginator.rb +42 -0
- data/lib/roundhouse/processor.rb +159 -0
- data/lib/roundhouse/rails.rb +24 -0
- data/lib/roundhouse/redis_connection.rb +77 -0
- data/lib/roundhouse/scheduled.rb +115 -0
- data/lib/roundhouse/testing/inline.rb +28 -0
- data/lib/roundhouse/testing.rb +193 -0
- data/lib/roundhouse/util.rb +68 -0
- data/lib/roundhouse/version.rb +3 -0
- data/lib/roundhouse/web.rb +264 -0
- data/lib/roundhouse/web_helpers.rb +249 -0
- data/lib/roundhouse/worker.rb +90 -0
- data/lib/roundhouse.rb +177 -0
- data/roundhouse.gemspec +27 -0
- data/test/config.yml +9 -0
- data/test/env_based_config.yml +11 -0
- data/test/fake_env.rb +0 -0
- data/test/fixtures/en.yml +2 -0
- data/test/helper.rb +49 -0
- data/test/test_api.rb +521 -0
- data/test/test_cli.rb +389 -0
- data/test/test_client.rb +294 -0
- data/test/test_exception_handler.rb +55 -0
- data/test/test_fetch.rb +206 -0
- data/test/test_logging.rb +34 -0
- data/test/test_manager.rb +169 -0
- data/test/test_middleware.rb +160 -0
- data/test/test_monitor.rb +258 -0
- data/test/test_processor.rb +176 -0
- data/test/test_rails.rb +23 -0
- data/test/test_redis_connection.rb +127 -0
- data/test/test_retry.rb +390 -0
- data/test/test_roundhouse.rb +87 -0
- data/test/test_scheduled.rb +120 -0
- data/test/test_scheduling.rb +75 -0
- data/test/test_testing.rb +78 -0
- data/test/test_testing_fake.rb +240 -0
- data/test/test_testing_inline.rb +65 -0
- data/test/test_util.rb +18 -0
- data/test/test_web.rb +605 -0
- data/test/test_web_helpers.rb +52 -0
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/logo.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/assets/images/status-sd8051fd480.png +0 -0
- data/web/assets/javascripts/application.js +83 -0
- data/web/assets/javascripts/dashboard.js +300 -0
- data/web/assets/javascripts/locales/README.md +27 -0
- data/web/assets/javascripts/locales/jquery.timeago.ar.js +96 -0
- data/web/assets/javascripts/locales/jquery.timeago.bg.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.bs.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.ca.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.cs.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.cy.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.da.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.de.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.el.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.en-short.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.en.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.es.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.et.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.fa.js +22 -0
- data/web/assets/javascripts/locales/jquery.timeago.fi.js +28 -0
- data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.fr.js +17 -0
- data/web/assets/javascripts/locales/jquery.timeago.he.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.hr.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.hu.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.hy.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.id.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.it.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.ja.js +19 -0
- data/web/assets/javascripts/locales/jquery.timeago.ko.js +17 -0
- data/web/assets/javascripts/locales/jquery.timeago.lt.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.mk.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.nl.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.no.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.pl.js +31 -0
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.pt.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.ro.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.rs.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.ru.js +34 -0
- data/web/assets/javascripts/locales/jquery.timeago.sk.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.sl.js +44 -0
- data/web/assets/javascripts/locales/jquery.timeago.sv.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.th.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.tr.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.uk.js +34 -0
- data/web/assets/javascripts/locales/jquery.timeago.uz.js +19 -0
- data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +20 -0
- data/web/assets/stylesheets/application.css +746 -0
- data/web/assets/stylesheets/bootstrap.css +9 -0
- data/web/locales/cs.yml +68 -0
- data/web/locales/da.yml +68 -0
- data/web/locales/de.yml +69 -0
- data/web/locales/el.yml +68 -0
- data/web/locales/en.yml +77 -0
- data/web/locales/es.yml +69 -0
- data/web/locales/fr.yml +69 -0
- data/web/locales/hi.yml +75 -0
- data/web/locales/it.yml +69 -0
- data/web/locales/ja.yml +69 -0
- data/web/locales/ko.yml +68 -0
- data/web/locales/nl.yml +68 -0
- data/web/locales/no.yml +69 -0
- data/web/locales/pl.yml +59 -0
- data/web/locales/pt-br.yml +68 -0
- data/web/locales/pt.yml +67 -0
- data/web/locales/ru.yml +75 -0
- data/web/locales/sv.yml +68 -0
- data/web/locales/ta.yml +75 -0
- data/web/locales/zh-cn.yml +68 -0
- data/web/locales/zh-tw.yml +68 -0
- data/web/views/_footer.erb +22 -0
- data/web/views/_job_info.erb +84 -0
- data/web/views/_nav.erb +66 -0
- data/web/views/_paging.erb +23 -0
- data/web/views/_poll_js.erb +5 -0
- data/web/views/_poll_link.erb +7 -0
- data/web/views/_status.erb +4 -0
- data/web/views/_summary.erb +40 -0
- data/web/views/busy.erb +90 -0
- data/web/views/dashboard.erb +75 -0
- data/web/views/dead.erb +34 -0
- data/web/views/layout.erb +31 -0
- data/web/views/morgue.erb +71 -0
- data/web/views/queue.erb +45 -0
- data/web/views/queues.erb +27 -0
- data/web/views/retries.erb +74 -0
- data/web/views/retry.erb +34 -0
- data/web/views/scheduled.erb +54 -0
- data/web/views/scheduled_job_info.erb +8 -0
- metadata +404 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
#require 'roundhouse/api'
|
|
3
|
+
require 'roundhouse/monitor'
|
|
4
|
+
|
|
5
|
+
require 'active_support/core_ext/numeric/time'
|
|
6
|
+
|
|
7
|
+
class TestMonitor < Roundhouse::Test
|
|
8
|
+
describe 'Roundhouse::Monitor' do
|
|
9
|
+
before do
|
|
10
|
+
Roundhouse.redis(&:flushdb)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#pop' do
|
|
14
|
+
describe 'when nominal' do
|
|
15
|
+
it 'should pop the next available job from the next available queue' do
|
|
16
|
+
Roundhouse.redis do |conn|
|
|
17
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
18
|
+
assert_equal '100', Roundhouse::Monitor.pop(conn)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'with queue with empty status' do
|
|
24
|
+
it 'should skip' do
|
|
25
|
+
Roundhouse.redis do |conn|
|
|
26
|
+
Roundhouse::Monitor.activate(conn, '200')
|
|
27
|
+
Roundhouse::Monitor.push(conn, '200')
|
|
28
|
+
Roundhouse::Monitor.set_queue_is_empty(conn, '200')
|
|
29
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
30
|
+
|
|
31
|
+
assert_equal '100', Roundhouse::Monitor.pop(conn)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe 'with empty queue with active status' do
|
|
37
|
+
it 'should not skip' do
|
|
38
|
+
Roundhouse.redis do |conn|
|
|
39
|
+
Roundhouse::Monitor.activate(conn, '200')
|
|
40
|
+
Roundhouse::Monitor.push(conn, '200')
|
|
41
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
42
|
+
|
|
43
|
+
assert_equal '200', Roundhouse::Monitor.pop(conn)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'with queue with suspended status' do
|
|
49
|
+
it 'should skip' do
|
|
50
|
+
Roundhouse.redis do |conn|
|
|
51
|
+
Roundhouse::Monitor.activate(conn, '200')
|
|
52
|
+
Roundhouse::Monitor.push(conn, '200')
|
|
53
|
+
Roundhouse::Monitor.suspend(conn, '200')
|
|
54
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
55
|
+
|
|
56
|
+
assert_equal '100', Roundhouse::Monitor.pop(conn)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe 'when no active queue is in semaphore' do
|
|
62
|
+
it 'should block' do
|
|
63
|
+
skip 'do not know how to test this, and this may not be the right design'
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end # #pop
|
|
67
|
+
|
|
68
|
+
describe '#push' do
|
|
69
|
+
describe 'with active queue' do
|
|
70
|
+
it 'should push into semaphore' do
|
|
71
|
+
Roundhouse.redis do |conn|
|
|
72
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
73
|
+
|
|
74
|
+
assert_equal ['100'], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe 'with queue with empty status' do
|
|
80
|
+
it 'should not push into semaphore' do
|
|
81
|
+
Roundhouse.redis do |conn|
|
|
82
|
+
Roundhouse::Monitor.set_queue_is_empty(conn, '200')
|
|
83
|
+
|
|
84
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe 'with queue with suspended status' do
|
|
90
|
+
it 'should skip' do
|
|
91
|
+
Roundhouse.redis do |conn|
|
|
92
|
+
Roundhouse::Monitor.suspend(conn, '200')
|
|
93
|
+
Roundhouse::Monitor.push(conn, '200')
|
|
94
|
+
|
|
95
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end # #push
|
|
100
|
+
|
|
101
|
+
describe '#pop_job' do
|
|
102
|
+
describe 'with jobs in queue' do
|
|
103
|
+
it 'should pop the next job and return data' do
|
|
104
|
+
Roundhouse.redis do |conn|
|
|
105
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 100, 'class' => 'MyWorker', 'args' => [1]}]
|
|
106
|
+
assert conn.lrange("#{Roundhouse::Monitor::QUEUE}:100", 0, 0).first
|
|
107
|
+
assert Roundhouse::Monitor.pop_job conn, 100
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe 'without jobs in queue' do
|
|
113
|
+
it 'should return nil' do
|
|
114
|
+
Roundhouse.redis do |conn|
|
|
115
|
+
refute conn.lrange("#{Roundhouse::Monitor::QUEUE}:100", 0, 0).first
|
|
116
|
+
refute Roundhouse::Monitor.pop_job conn, 100
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe '#push_job' do
|
|
123
|
+
it 'should add bucket and push to queue' do
|
|
124
|
+
Roundhouse.redis do |conn|
|
|
125
|
+
bucket_num = Roundhouse::Monitor.bucket_num(2500)
|
|
126
|
+
refute conn.sismember(Roundhouse::Monitor::BUCKETS, bucket_num)
|
|
127
|
+
refute conn.lrange("#{Roundhouse::Monitor::QUEUE}:2500", 0, 0).first
|
|
128
|
+
|
|
129
|
+
Roundhouse::Monitor.push_job conn, [{'queue_id' => 2500, 'class' => 'MyWorker', 'args' => [1]}]
|
|
130
|
+
|
|
131
|
+
# We should see the bucket registered
|
|
132
|
+
assert conn.sismember(Roundhouse::Monitor::BUCKETS, bucket_num)
|
|
133
|
+
assert conn.lrange("#{Roundhouse::Monitor::QUEUE}:2500", 0, 0).first
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe '#requeue' do
|
|
140
|
+
it 'should requeue items'
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe '#maybe_add_to_rotation' do
|
|
144
|
+
describe 'with active queue' do
|
|
145
|
+
it 'should not rotate queue into semaphore' do
|
|
146
|
+
Roundhouse.redis do |conn|
|
|
147
|
+
Roundhouse::Monitor.activate(conn, 100)
|
|
148
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
149
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
150
|
+
|
|
151
|
+
Roundhouse::Monitor.maybe_add_to_rotation(conn, 100)
|
|
152
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
153
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe 'with empty queue' do
|
|
159
|
+
it 'should rotate queue into semaphore' do
|
|
160
|
+
Roundhouse.redis do |conn|
|
|
161
|
+
Roundhouse::Monitor.set_queue_is_empty(conn, 100)
|
|
162
|
+
assert_equal Roundhouse::Monitor::EMPTY, Roundhouse::Monitor.queue_status(conn, 100)
|
|
163
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
164
|
+
|
|
165
|
+
Roundhouse::Monitor.maybe_add_to_rotation(conn, 100)
|
|
166
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
167
|
+
assert_equal ['100'], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
describe 'with suspended queue' do
|
|
173
|
+
it 'should not rotate queue into semaphore' do
|
|
174
|
+
Roundhouse.redis do |conn|
|
|
175
|
+
Roundhouse::Monitor.suspend(conn, 100)
|
|
176
|
+
assert_equal Roundhouse::Monitor::SUSPENDED, Roundhouse::Monitor.queue_status(conn, 100)
|
|
177
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
178
|
+
|
|
179
|
+
Roundhouse::Monitor.maybe_add_to_rotation(conn, 100)
|
|
180
|
+
assert_equal Roundhouse::Monitor::SUSPENDED, Roundhouse::Monitor.queue_status(conn, 100)
|
|
181
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, 0, 0)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end # maybe_add_to_rotation
|
|
186
|
+
|
|
187
|
+
describe '#set_queue_is_empty' do
|
|
188
|
+
it 'should set queue as empty' do
|
|
189
|
+
Roundhouse.redis do |conn|
|
|
190
|
+
Roundhouse::Monitor.set_queue_is_empty(conn, 100)
|
|
191
|
+
assert_equal Roundhouse::Monitor::EMPTY, Roundhouse::Monitor.queue_status(conn, 100)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end # #set_queue_is_empty
|
|
195
|
+
|
|
196
|
+
describe '#activate' do
|
|
197
|
+
it 'should set queue as active' do
|
|
198
|
+
Roundhouse.redis do |conn|
|
|
199
|
+
Roundhouse::Monitor.activate(conn, 100)
|
|
200
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end # #activate
|
|
204
|
+
|
|
205
|
+
describe '#suspend' do
|
|
206
|
+
it 'should set queue as suspended' do
|
|
207
|
+
Roundhouse.redis do |conn|
|
|
208
|
+
Roundhouse::Monitor.suspend(conn, 100)
|
|
209
|
+
assert_equal Roundhouse::Monitor::SUSPENDED, Roundhouse::Monitor.queue_status(conn, 100)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end # #suspend
|
|
213
|
+
|
|
214
|
+
describe '#resume' do
|
|
215
|
+
describe 'with suspended queue' do
|
|
216
|
+
it 'should reactive queue and put it into rotation' do
|
|
217
|
+
Roundhouse.redis do |conn|
|
|
218
|
+
Roundhouse::Monitor.suspend(conn, 100)
|
|
219
|
+
assert_equal Roundhouse::Monitor::SUSPENDED, Roundhouse::Monitor.queue_status(conn, 100)
|
|
220
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
221
|
+
|
|
222
|
+
Roundhouse::Monitor.resume(conn, 100)
|
|
223
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
224
|
+
assert_equal ['100'], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
describe 'with empty queue' do
|
|
230
|
+
it 'should not resume' do
|
|
231
|
+
Roundhouse.redis do |conn|
|
|
232
|
+
Roundhouse::Monitor.set_queue_is_empty(conn, 100)
|
|
233
|
+
assert_equal Roundhouse::Monitor::EMPTY, Roundhouse::Monitor.queue_status(conn, 100)
|
|
234
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
235
|
+
|
|
236
|
+
Roundhouse::Monitor.resume(conn, 100)
|
|
237
|
+
assert_equal Roundhouse::Monitor::EMPTY, Roundhouse::Monitor.queue_status(conn, 100)
|
|
238
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe 'with active queue' do
|
|
244
|
+
it 'should not resume' do
|
|
245
|
+
Roundhouse.redis do |conn|
|
|
246
|
+
Roundhouse::Monitor.activate(conn, 100)
|
|
247
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
248
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
249
|
+
|
|
250
|
+
Roundhouse::Monitor.resume(conn, 100)
|
|
251
|
+
assert_equal Roundhouse::Monitor::ACTIVE, Roundhouse::Monitor.queue_status(conn, 100)
|
|
252
|
+
assert_equal [], conn.lrange(Roundhouse::Monitor::SEMAPHORE, -1, -1)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end # #resume
|
|
257
|
+
end
|
|
258
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
require 'roundhouse/processor'
|
|
3
|
+
require 'roundhouse/fetch'
|
|
4
|
+
require 'roundhouse/cli'
|
|
5
|
+
|
|
6
|
+
class TestProcessor < Roundhouse::Test
|
|
7
|
+
TestException = Class.new(StandardError)
|
|
8
|
+
TEST_EXCEPTION = TestException.new("kerboom!")
|
|
9
|
+
|
|
10
|
+
describe 'with mock setup' do
|
|
11
|
+
before do
|
|
12
|
+
$invokes = 0
|
|
13
|
+
@boss = Minitest::Mock.new
|
|
14
|
+
@processor = ::Roundhouse::Processor.new(@boss)
|
|
15
|
+
Celluloid.logger = nil
|
|
16
|
+
Roundhouse.redis = REDIS
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class MockWorker
|
|
20
|
+
include Roundhouse::Worker
|
|
21
|
+
def perform(args)
|
|
22
|
+
raise TEST_EXCEPTION if args == 'boom'
|
|
23
|
+
args.pop if args.is_a? Array
|
|
24
|
+
$invokes += 1
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def work(msg, full_queue_name='queue:100')
|
|
29
|
+
Roundhouse::RoundRobinFetch::UnitOfWork.new(full_queue_name, msg)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'processes as expected' do
|
|
33
|
+
# Queue needs to be active or it won't be put back into rotation
|
|
34
|
+
Roundhouse.redis { |conn| Roundhouse::Monitor.activate(conn, 100) }
|
|
35
|
+
|
|
36
|
+
msg = Roundhouse.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
|
37
|
+
actor = Minitest::Mock.new
|
|
38
|
+
actor.expect(:processor_done, nil, [@processor])
|
|
39
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
40
|
+
@boss.expect(:async, actor, [])
|
|
41
|
+
@boss.expect(:async, actor, [])
|
|
42
|
+
@processor.process(work(msg))
|
|
43
|
+
|
|
44
|
+
# After being finished, the q_id should be put back into the semaphore
|
|
45
|
+
queue_id = Roundhouse.redis { |conn| conn.lrange('semaphore', 0, 0).first }
|
|
46
|
+
assert_equal '100', queue_id
|
|
47
|
+
|
|
48
|
+
@boss.verify
|
|
49
|
+
assert_equal 1, $invokes
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'executes a worker as expected' do
|
|
53
|
+
worker = Minitest::Mock.new
|
|
54
|
+
worker.expect(:perform, nil, [1, 2, 3])
|
|
55
|
+
@processor.execute_job(worker, [1, 2, 3])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'passes exceptions to ExceptionHandler' do
|
|
59
|
+
actor = Minitest::Mock.new
|
|
60
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
61
|
+
@boss.expect(:async, actor, [])
|
|
62
|
+
msg = Roundhouse.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
|
63
|
+
begin
|
|
64
|
+
@processor.process(work(msg))
|
|
65
|
+
flunk "Expected #process to raise exception"
|
|
66
|
+
rescue TestException
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
assert_equal 0, $invokes
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 're-raises exceptions after handling' do
|
|
73
|
+
msg = Roundhouse.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
|
74
|
+
re_raise = false
|
|
75
|
+
actor = Minitest::Mock.new
|
|
76
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
77
|
+
@boss.expect(:async, actor, [])
|
|
78
|
+
|
|
79
|
+
begin
|
|
80
|
+
@processor.process(work(msg))
|
|
81
|
+
rescue TestException
|
|
82
|
+
re_raise = true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
assert re_raise, "does not re-raise exceptions after handling"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'does not modify original arguments' do
|
|
89
|
+
msg = { 'class' => MockWorker.to_s, 'args' => [['myarg']] }
|
|
90
|
+
msgstr = Roundhouse.dump_json(msg)
|
|
91
|
+
processor = ::Roundhouse::Processor.new(@boss)
|
|
92
|
+
actor = Minitest::Mock.new
|
|
93
|
+
actor.expect(:processor_done, nil, [processor])
|
|
94
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
95
|
+
@boss.expect(:async, actor, [])
|
|
96
|
+
@boss.expect(:async, actor, [])
|
|
97
|
+
processor.process(work(msgstr))
|
|
98
|
+
assert_equal [['myarg']], msg['args']
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe 'stats' do
|
|
102
|
+
before do
|
|
103
|
+
Roundhouse.redis {|c| c.flushdb }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def with_expire(time)
|
|
107
|
+
begin
|
|
108
|
+
old = Roundhouse::Processor::STATS_TIMEOUT
|
|
109
|
+
silence_warnings { Roundhouse::Processor.const_set(:STATS_TIMEOUT, time) }
|
|
110
|
+
yield
|
|
111
|
+
ensure
|
|
112
|
+
silence_warnings { Roundhouse::Processor.const_set(:STATS_TIMEOUT, old) }
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe 'when successful' do
|
|
117
|
+
let(:processed_today_key) { "stat:processed:#{Time.now.utc.to_date}" }
|
|
118
|
+
|
|
119
|
+
def successful_job
|
|
120
|
+
msg = Roundhouse.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
|
121
|
+
actor = Minitest::Mock.new
|
|
122
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
123
|
+
actor.expect(:processor_done, nil, [@processor])
|
|
124
|
+
@boss.expect(:async, actor, [])
|
|
125
|
+
@boss.expect(:async, actor, [])
|
|
126
|
+
@processor.process(work(msg))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it 'increments processed stat' do
|
|
130
|
+
successful_job
|
|
131
|
+
assert_equal 1, Roundhouse::Stats.new.processed
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'expires processed stat' do
|
|
135
|
+
successful_job
|
|
136
|
+
assert_equal Roundhouse::Processor::STATS_TIMEOUT, Roundhouse.redis { |conn| conn.ttl(processed_today_key) }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'increments date processed stat' do
|
|
140
|
+
successful_job
|
|
141
|
+
assert_equal 1, Roundhouse.redis { |conn| conn.get(processed_today_key) }.to_i
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe 'when failed' do
|
|
146
|
+
let(:failed_today_key) { "stat:failed:#{Time.now.utc.to_date}" }
|
|
147
|
+
|
|
148
|
+
def failed_job
|
|
149
|
+
actor = Minitest::Mock.new
|
|
150
|
+
actor.expect(:real_thread, nil, [nil, Thread])
|
|
151
|
+
@boss.expect(:async, actor, [])
|
|
152
|
+
msg = Roundhouse.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
|
153
|
+
begin
|
|
154
|
+
@processor.process(work(msg))
|
|
155
|
+
rescue TestException
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'increments failed stat' do
|
|
160
|
+
failed_job
|
|
161
|
+
assert_equal 1, Roundhouse::Stats.new.failed
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it 'increments date failed stat' do
|
|
165
|
+
failed_job
|
|
166
|
+
assert_equal 1, Roundhouse.redis { |conn| conn.get(failed_today_key) }.to_i
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'expires failed stat' do
|
|
170
|
+
failed_job
|
|
171
|
+
assert_equal Roundhouse::Processor::STATS_TIMEOUT, Roundhouse.redis { |conn| conn.ttl(failed_today_key) }
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
data/test/test_rails.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
require 'roundhouse'
|
|
3
|
+
require 'roundhouse/web_helpers'
|
|
4
|
+
|
|
5
|
+
$HAS_AJ = true
|
|
6
|
+
begin
|
|
7
|
+
require 'active_job'
|
|
8
|
+
rescue LoadError
|
|
9
|
+
$HAS_AJ = false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class TestRails < Roundhouse::Test
|
|
13
|
+
|
|
14
|
+
describe 'ActiveJob' do
|
|
15
|
+
it 'does not allow Roundhouse::Worker in AJ::Base classes' do
|
|
16
|
+
ex = assert_raises ArgumentError do
|
|
17
|
+
c = Class.new(ActiveJob::Base)
|
|
18
|
+
c.send(:include, Roundhouse::Worker)
|
|
19
|
+
end
|
|
20
|
+
assert_includes ex.message, "cannot include"
|
|
21
|
+
end if $HAS_AJ
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
require 'roundhouse/redis_connection'
|
|
3
|
+
|
|
4
|
+
class TestRedisConnection < Roundhouse::Test
|
|
5
|
+
|
|
6
|
+
describe ".create" do
|
|
7
|
+
|
|
8
|
+
it "creates a pooled redis connection" do
|
|
9
|
+
pool = Roundhouse::RedisConnection.create
|
|
10
|
+
assert_equal Redis, pool.checkout.class
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "network_timeout" do
|
|
14
|
+
it "sets a custom network_timeout if specified" do
|
|
15
|
+
pool = Roundhouse::RedisConnection.create(:network_timeout => 8)
|
|
16
|
+
redis = pool.checkout
|
|
17
|
+
|
|
18
|
+
assert_equal 8, redis.client.timeout
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "uses the default network_timeout if none specified" do
|
|
22
|
+
pool = Roundhouse::RedisConnection.create
|
|
23
|
+
redis = pool.checkout
|
|
24
|
+
|
|
25
|
+
assert_equal 5, redis.client.timeout
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "namespace" do
|
|
30
|
+
it "uses a given :namespace" do
|
|
31
|
+
pool = Roundhouse::RedisConnection.create(:namespace => "xxx")
|
|
32
|
+
assert_equal "xxx", pool.checkout.namespace
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "uses given :namespace over :namespace from Roundhouse.options" do
|
|
36
|
+
Roundhouse.options[:namespace] = "xxx"
|
|
37
|
+
pool = Roundhouse::RedisConnection.create(:namespace => "yyy")
|
|
38
|
+
assert_equal "yyy", pool.checkout.namespace
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "socket path" do
|
|
43
|
+
it "uses a given :path" do
|
|
44
|
+
pool = Roundhouse::RedisConnection.create(:path => "/var/run/redis.sock")
|
|
45
|
+
assert_equal "unix", pool.checkout.client.scheme
|
|
46
|
+
assert_equal "redis:///var/run/redis.sock/0", pool.checkout.client.id
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "uses a given :path and :db" do
|
|
50
|
+
pool = Roundhouse::RedisConnection.create(:path => "/var/run/redis.sock", :db => 8)
|
|
51
|
+
assert_equal "unix", pool.checkout.client.scheme
|
|
52
|
+
assert_equal "redis:///var/run/redis.sock/8", pool.checkout.client.id
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "pool_timeout" do
|
|
57
|
+
it "uses a given :timeout over the default of 1" do
|
|
58
|
+
pool = Roundhouse::RedisConnection.create(:pool_timeout => 5)
|
|
59
|
+
|
|
60
|
+
assert_equal 5, pool.instance_eval{ @timeout }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "uses the default timeout of 1 if no override" do
|
|
64
|
+
pool = Roundhouse::RedisConnection.create
|
|
65
|
+
|
|
66
|
+
assert_equal 1, pool.instance_eval{ @timeout }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe ".determine_redis_provider" do
|
|
72
|
+
|
|
73
|
+
before do
|
|
74
|
+
@old_env = ENV.to_hash
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
after do
|
|
78
|
+
ENV.update(@old_env)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def with_env_var(var, uri, skip_provider=false)
|
|
82
|
+
vars = ['REDISTOGO_URL', 'REDIS_PROVIDER', 'REDIS_URL'] - [var]
|
|
83
|
+
vars.each do |v|
|
|
84
|
+
next if skip_provider
|
|
85
|
+
ENV[v] = nil
|
|
86
|
+
end
|
|
87
|
+
ENV[var] = uri
|
|
88
|
+
assert_equal uri, Roundhouse::RedisConnection.__send__(:determine_redis_provider)
|
|
89
|
+
ENV[var] = nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "with REDISTOGO_URL and a parallel REDIS_PROVIDER set" do
|
|
93
|
+
it "sets connection URI to the provider" do
|
|
94
|
+
uri = 'redis://roundhouse-redis-provider:6379/0'
|
|
95
|
+
provider = 'SIDEKIQ_REDIS_PROVIDER'
|
|
96
|
+
|
|
97
|
+
ENV['REDIS_PROVIDER'] = provider
|
|
98
|
+
ENV[provider] = uri
|
|
99
|
+
ENV['REDISTOGO_URL'] = 'redis://redis-to-go:6379/0'
|
|
100
|
+
with_env_var provider, uri, true
|
|
101
|
+
|
|
102
|
+
ENV[provider] = nil
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "with REDIS_PROVIDER set" do
|
|
107
|
+
it "sets connection URI to the provider" do
|
|
108
|
+
uri = 'redis://roundhouse-redis-provider:6379/0'
|
|
109
|
+
provider = 'SIDEKIQ_REDIS_PROVIDER'
|
|
110
|
+
|
|
111
|
+
ENV['REDIS_PROVIDER'] = provider
|
|
112
|
+
ENV[provider] = uri
|
|
113
|
+
|
|
114
|
+
with_env_var provider, uri, true
|
|
115
|
+
|
|
116
|
+
ENV[provider] = nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe "with REDIS_URL set" do
|
|
121
|
+
it "sets connection URI to custom uri" do
|
|
122
|
+
with_env_var 'REDIS_URL', 'redis://redis-uri:6379/0'
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
end
|