sidetiq 0.2.0 → 0.3.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.
- data/.gitignore +1 -0
- data/CHANGELOG.md +12 -0
- data/README.md +205 -9
- data/lib/sidetiq.rb +118 -1
- data/lib/sidetiq/clock.rb +33 -30
- data/lib/sidetiq/middleware.rb +1 -1
- data/lib/sidetiq/schedulable.rb +13 -8
- data/lib/sidetiq/schedule.rb +58 -6
- data/lib/sidetiq/version.rb +1 -1
- data/test/fixtures/backfill_worker.rb +11 -0
- data/test/fixtures/last_and_scheduled_ticks_worker.rb +5 -0
- data/test/fixtures/last_tick_worker.rb +5 -0
- data/test/fixtures/scheduled_worker.rb +16 -0
- data/test/fixtures/simple_worker.rb +8 -0
- data/test/fixtures/splat_args_worker.rb +5 -0
- data/test/helper.rb +17 -2
- data/test/test_clock.rb +32 -30
- data/test/test_schedule.rb +17 -4
- data/test/test_sidetiq.rb +125 -0
- data/test/test_web.rb +5 -18
- data/test/test_worker.rb +4 -0
- metadata +16 -2
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.3.0
|
2
|
+
-----
|
3
|
+
|
4
|
+
- Add `Sidetiq.schedules`.
|
5
|
+
- Add `Sidetiq.workers`.
|
6
|
+
- Add `Sidetiq.scheduled`.
|
7
|
+
- Add `Sidetiq.retries`.
|
8
|
+
- Add `Sidetiq.logger`. This defaults to the Sidekiq logger.
|
9
|
+
- Add support for job backfills.
|
10
|
+
- Clean up tests.
|
11
|
+
- Sidetiq::Schedule no longer inherits from IceCube::Schedule.
|
12
|
+
|
1
13
|
0.2.0
|
2
14
|
-----
|
3
15
|
|
data/README.md
CHANGED
@@ -6,7 +6,27 @@ Sidetiq
|
|
6
6
|
|
7
7
|
Recurring jobs for [Sidekiq](http://mperham.github.com/sidekiq/).
|
8
8
|
|
9
|
-
|
9
|
+
Table Of Contents
|
10
|
+
-----------------
|
11
|
+
|
12
|
+
* [Overview](#section_Overview)
|
13
|
+
* [Dependencies](#section_Dependencies)
|
14
|
+
* [Installation](#section_Installation)
|
15
|
+
* [Introduction](#section_Introduction)
|
16
|
+
* [Backfills](#section_Backfills)
|
17
|
+
* [Configuration](#section_Configuration)
|
18
|
+
* [Logging](#section_Configuration_Logging)
|
19
|
+
* [API](#section_API)
|
20
|
+
* [Polling](#section_Polling)
|
21
|
+
* [Known Issues](#section_Known_Issues)
|
22
|
+
* [Web Extension](#section_Web_Extension)
|
23
|
+
* [Contribute](#section_Contribute)
|
24
|
+
* [License](#section_License)
|
25
|
+
* [Author](#section_Author)
|
26
|
+
|
27
|
+
<a name='section_Overview'></a>
|
28
|
+
Overview
|
29
|
+
--------
|
10
30
|
|
11
31
|
Sidetiq provides a simple API for defining recurring workers for Sidekiq.
|
12
32
|
|
@@ -20,12 +40,18 @@ Sidetiq provides a simple API for defining recurring workers for Sidekiq.
|
|
20
40
|
each other (tested with sub-second polling of scheduled jobs by Sidekiq and
|
21
41
|
Sidetiq clock rates above 100hz).
|
22
42
|
|
23
|
-
|
43
|
+
Detailed API documentation is available on [rubydoc.info](http://rdoc.info/github/tobiassvn/sidetiq/).
|
44
|
+
|
45
|
+
<a name='section_Dependencies'></a>
|
46
|
+
Dependencies
|
47
|
+
------------
|
24
48
|
|
25
49
|
- [Sidekiq](http://mperham.github.com/sidekiq/)
|
26
50
|
- [ice_cube](http://seejohnrun.github.com/ice_cube/)
|
27
51
|
|
28
|
-
|
52
|
+
<a name='section_Installation'></a>
|
53
|
+
Installation
|
54
|
+
------------
|
29
55
|
|
30
56
|
The best way to install Sidetiq is with RubyGems:
|
31
57
|
|
@@ -36,7 +62,9 @@ to pick up all the gems ([more info](http://gembundler.com/bundle_install.html))
|
|
36
62
|
|
37
63
|
$ bundle install
|
38
64
|
|
39
|
-
|
65
|
+
<a name='section_Introduction'></a>
|
66
|
+
Introduction
|
67
|
+
------------
|
40
68
|
|
41
69
|
Defining recurring jobs is simple:
|
42
70
|
|
@@ -47,6 +75,10 @@ class MyWorker
|
|
47
75
|
|
48
76
|
# Daily at midnight
|
49
77
|
tiq { daily }
|
78
|
+
|
79
|
+
def perform
|
80
|
+
# do stuff ...
|
81
|
+
end
|
50
82
|
end
|
51
83
|
```
|
52
84
|
|
@@ -64,6 +96,10 @@ class MyWorker
|
|
64
96
|
# Every second year in February
|
65
97
|
yearly(2).month_of_year(:february)
|
66
98
|
end
|
99
|
+
|
100
|
+
def perform
|
101
|
+
# do stuff ...
|
102
|
+
end
|
67
103
|
end
|
68
104
|
```
|
69
105
|
|
@@ -76,6 +112,28 @@ class MyWorker
|
|
76
112
|
|
77
113
|
# Every other month on the first monday and last tuesday at 12 o'clock.
|
78
114
|
tiq { monthly(2).day_of_week(1 => [1], 2 => [-1]).hour_of_day(12) }
|
115
|
+
|
116
|
+
def perform
|
117
|
+
# do stuff ...
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Additionally, the last and current occurrence time (as a `Float`) can be
|
123
|
+
passed to the worker simply by adding arguments to `#perform`. Sidetiq
|
124
|
+
will check the method arity before enqueuing the job:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
class MyWorker
|
128
|
+
include Sidekiq::Worker
|
129
|
+
include Sidetiq::Schedulable
|
130
|
+
|
131
|
+
tiq { daily }
|
132
|
+
|
133
|
+
# Receive last and current occurrence times.
|
134
|
+
def perform(last_occurrence, current_occurrence)
|
135
|
+
# do stuff ...
|
136
|
+
end
|
79
137
|
end
|
80
138
|
```
|
81
139
|
|
@@ -91,7 +149,35 @@ end
|
|
91
149
|
Additionally, Sidetiq includes a middleware that will check if the clock
|
92
150
|
thread is still alive and restart it if necessary.
|
93
151
|
|
94
|
-
|
152
|
+
<a name='section_Backfills''></a>
|
153
|
+
Backfills
|
154
|
+
---------
|
155
|
+
|
156
|
+
In certain cases it is desirable that missed jobs will be enqueued
|
157
|
+
retroactively, for example when a critical, hourly job isn't run due to
|
158
|
+
server downtime. To solve this, `#tiq` takes a *backfill* option. If
|
159
|
+
missing job occurrences have been detected, Sidetiq will then enqueue
|
160
|
+
the jobs automatically. It will also ensure that the timestamps passed to
|
161
|
+
`#perform` are as expected:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
class MyWorker
|
165
|
+
include Sidekiq::Worker
|
166
|
+
include Sidetiq::Schedulable
|
167
|
+
|
168
|
+
tiq backfill: true do
|
169
|
+
hourly
|
170
|
+
end
|
171
|
+
|
172
|
+
def perform(last_occurrence, current_occurrence)
|
173
|
+
# do stuff ...
|
174
|
+
end
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
<a name='section_Configuration'></a>
|
179
|
+
Configuration
|
180
|
+
-------------
|
95
181
|
|
96
182
|
```ruby
|
97
183
|
Sidetiq.configure do |config|
|
@@ -109,8 +195,71 @@ Sidetiq.configure do |config|
|
|
109
195
|
config.utc = false
|
110
196
|
end
|
111
197
|
```
|
198
|
+
<a name='section_Configuration_Logging'></a>
|
199
|
+
### Logging
|
200
|
+
|
201
|
+
By default Sidetiq uses Sidekiq's logger. However, this is configuration:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
Sidetiq.logger = Logger.new(STDOUT)
|
205
|
+
```
|
206
|
+
|
207
|
+
The logger should implement Ruby's [Logger API](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html).
|
208
|
+
|
209
|
+
<a name='section_API'></a>
|
210
|
+
API
|
211
|
+
---
|
212
|
+
|
213
|
+
Sidetiq implements a simple API to support reflection of recurring jobs at
|
214
|
+
runtime:
|
215
|
+
|
216
|
+
`Sidetiq.schedules` returns a `Hash` with the `Sidekiq::Worker` class as the
|
217
|
+
key and the Sidetiq::Schedule object as the value:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
Sidetiq.schedules
|
221
|
+
# => { MyWorker => #<Sidetiq::Schedule> }
|
222
|
+
```
|
223
|
+
|
224
|
+
`Sidetiq.workers` returns an `Array` of all workers currently tracked by
|
225
|
+
Sidetiq (workers which include `Sidetiq::Schedulable` and a `.tiq` call):
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
Sidetiq.workers
|
229
|
+
# => [MyWorker, AnotherWorker]
|
230
|
+
```
|
231
|
+
|
232
|
+
`Sidetiq.scheduled` returns an `Array` of currently scheduled Sidetiq jobs
|
233
|
+
as `Sidekiq::SortedEntry` (`Sidekiq::Job`) objects. Optionally, it is
|
234
|
+
possible to pass a block to which each job will be yielded:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
Sidetiq.scheduled do |job|
|
238
|
+
# do stuff ...
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
This list can further be filtered by passing the worker class to `#scheduled`,
|
243
|
+
either as a String or the constant itself:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
Sidetiq.scheduled(MyWorker) do |job|
|
247
|
+
# do stuff ...
|
248
|
+
end
|
249
|
+
```
|
112
250
|
|
113
|
-
|
251
|
+
The same can be done for recurring jobs currently scheduled for retries
|
252
|
+
(`.retries` wraps `Sidekiq::RetrySet` instead of `Sidekiq::ScheduledSet`):
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
Sidetiq.retries(MyWorker) do |job|
|
256
|
+
# do stuff ...
|
257
|
+
end
|
258
|
+
```
|
259
|
+
|
260
|
+
<a name='section_Polling'></a>
|
261
|
+
Polling
|
262
|
+
-------
|
114
263
|
|
115
264
|
By default Sidekiq uses a 15 second polling interval to check if scheduled
|
116
265
|
jobs are due. If a recurring job has to run more often than that you should
|
@@ -120,7 +269,43 @@ lower this value.
|
|
120
269
|
Sidekiq.options[:poll_interval] = 1
|
121
270
|
```
|
122
271
|
|
123
|
-
|
272
|
+
More information about this can be found in the
|
273
|
+
[Sidekiq Wiki](https://github.com/mperham/sidekiq/wiki/Scheduled-Jobs).
|
274
|
+
|
275
|
+
<a name='section_Known_Issues'></a>
|
276
|
+
Known Issues
|
277
|
+
------------
|
278
|
+
|
279
|
+
Unfortunately, using ice_cube's interval methods is terribly slow on
|
280
|
+
start-up (it tends to eat up 100% CPU for quite a while). This is due to it
|
281
|
+
calculating every possible occurrence since the schedule's start time. The way
|
282
|
+
around is to avoid using them.
|
283
|
+
|
284
|
+
For example, instead of defining a job that should run every 15 minutes like this:
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
class MyWorker
|
288
|
+
include Sidekiq::Worker
|
289
|
+
include Sidetiq::Schedulable
|
290
|
+
|
291
|
+
tiq { minutely(15) }
|
292
|
+
end
|
293
|
+
```
|
294
|
+
|
295
|
+
It is better to use the more explicit way:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
class MyWorker
|
299
|
+
include Sidekiq::Worker
|
300
|
+
include Sidetiq::Schedulable
|
301
|
+
|
302
|
+
tiq { hourly.minute_of_hour(0, 15, 30, 45) }
|
303
|
+
end
|
304
|
+
```
|
305
|
+
|
306
|
+
<a name='section_Web_Extension'></a>
|
307
|
+
Web Extension
|
308
|
+
-------------
|
124
309
|
|
125
310
|
Sidetiq includes an extension for Sidekiq's web interface. It will not be
|
126
311
|
loaded by default, so it will have to be required manually:
|
@@ -133,7 +318,9 @@ require 'sidetiq/web'
|
|
133
318
|
|
134
319
|

|
135
320
|
|
136
|
-
|
321
|
+
<a name='section_Contribute'></a>
|
322
|
+
Contribute
|
323
|
+
----------
|
137
324
|
|
138
325
|
If you'd like to contribute to Sidetiq, start by forking my repo on GitHub:
|
139
326
|
|
@@ -152,6 +339,15 @@ your changes merged back into core is as follows:
|
|
152
339
|
1. Push the branch up to GitHub
|
153
340
|
1. Send a pull request to the tobiassvn/sidetiq project.
|
154
341
|
|
155
|
-
|
342
|
+
<a name='section_License'></a>
|
343
|
+
License
|
344
|
+
-------
|
156
345
|
|
157
346
|
Sidetiq is released under the MIT License. See LICENSE for further details.
|
347
|
+
|
348
|
+
<a name='section_Author'></a>
|
349
|
+
Author
|
350
|
+
------
|
351
|
+
|
352
|
+
Tobias Svensson, [@tobiassvn](https://twitter.com/tobiassvn), [http://github.com/tobiassvn](http://github.com/tobiassvn)
|
353
|
+
|
data/lib/sidetiq.rb
CHANGED
@@ -20,5 +20,122 @@ require 'sidetiq/version'
|
|
20
20
|
|
21
21
|
# The Sidetiq namespace.
|
22
22
|
module Sidetiq
|
23
|
-
|
23
|
+
class << self
|
24
|
+
# Public: Setter for the Sidetiq logger.
|
25
|
+
attr_writer :logger
|
26
|
+
|
27
|
+
# Public: Reader for the Sidetiq logger.
|
28
|
+
#
|
29
|
+
# Defaults to `Sidekiq.logger`.
|
30
|
+
def logger
|
31
|
+
@logger ||= Sidekiq.logger
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Returns an Array of workers including Sidetiq::Schedulable.
|
35
|
+
def workers
|
36
|
+
schedules.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
# Public: Returns a Hash of Sidetiq::Schedule instances.
|
40
|
+
def schedules
|
41
|
+
Clock.synchronize do
|
42
|
+
Clock.schedules.dup
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public: Currently scheduled recurring jobs.
|
47
|
+
#
|
48
|
+
# worker - A Sidekiq::Worker class or String of the class name (optional)
|
49
|
+
# block - An optional block that can be given to which each
|
50
|
+
# Sidekiq::SortedEntry instance corresponding to a scheduled job will
|
51
|
+
# be yielded.
|
52
|
+
#
|
53
|
+
# Examples
|
54
|
+
#
|
55
|
+
# Sidetiq.scheduled
|
56
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
57
|
+
#
|
58
|
+
# Sidetiq.scheduled(MyWorker)
|
59
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
60
|
+
#
|
61
|
+
# Sidetiq.scheduled("MyWorker")
|
62
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
63
|
+
#
|
64
|
+
# Sidetiq.scheduled do |job|
|
65
|
+
# # do stuff ...
|
66
|
+
# end
|
67
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
68
|
+
#
|
69
|
+
# Sidetiq.scheduled(MyWorker) do |job|
|
70
|
+
# # do stuff ...
|
71
|
+
# end
|
72
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
73
|
+
#
|
74
|
+
# Sidetiq.scheduled("MyWorker") do |job|
|
75
|
+
# # do stuff ...
|
76
|
+
# end
|
77
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
78
|
+
#
|
79
|
+
# Yields each Sidekiq::SortedEntry instance.
|
80
|
+
# Returns an Array of Sidekiq::SortedEntry objects.
|
81
|
+
def scheduled(worker = nil, &block)
|
82
|
+
filter_set(Sidekiq::ScheduledSet.new, worker, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Public: Recurring jobs currently scheduled for retries.
|
86
|
+
#
|
87
|
+
# worker - A Sidekiq::Worker class or String of the class name (optional)
|
88
|
+
# block - An optional block that can be given to which each
|
89
|
+
# Sidekiq::SortedEntry instance corresponding to a scheduled job will
|
90
|
+
# be yielded.
|
91
|
+
#
|
92
|
+
# Examples
|
93
|
+
#
|
94
|
+
# Sidetiq.retries
|
95
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
96
|
+
#
|
97
|
+
# Sidetiq.retries(MyWorker)
|
98
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
99
|
+
#
|
100
|
+
# Sidetiq.retries("MyWorker")
|
101
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
102
|
+
#
|
103
|
+
# Sidetiq.retries do |job|
|
104
|
+
# # do stuff ...
|
105
|
+
# end
|
106
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
107
|
+
#
|
108
|
+
# Sidetiq.retries(MyWorker) do |job|
|
109
|
+
# # do stuff ...
|
110
|
+
# end
|
111
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
112
|
+
#
|
113
|
+
# Sidetiq.retries("MyWorker") do |job|
|
114
|
+
# # do stuff ...
|
115
|
+
# end
|
116
|
+
# # => [#<Sidekiq::SortedEntry>, ...]
|
117
|
+
#
|
118
|
+
# Yields each Sidekiq::SortedEntry instance.
|
119
|
+
# Returns an Array of Sidekiq::SortedEntry objects.
|
120
|
+
def retries(worker = nil, &block)
|
121
|
+
filter_set(Sidekiq::RetrySet.new, worker, &block)
|
122
|
+
end
|
24
123
|
|
124
|
+
private
|
125
|
+
|
126
|
+
def filter_set(set, worker, &block)
|
127
|
+
worker = worker.constantize if worker.kind_of?(String)
|
128
|
+
|
129
|
+
jobs = set.select do |job|
|
130
|
+
klass = job.klass.constantize
|
131
|
+
ret = klass.include?(Schedulable)
|
132
|
+
ret = ret && klass == worker if worker
|
133
|
+
ret
|
134
|
+
end
|
135
|
+
|
136
|
+
jobs.each(&block) if block_given?
|
137
|
+
|
138
|
+
jobs
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/sidetiq/clock.rb
CHANGED
@@ -11,14 +11,10 @@ module Sidetiq
|
|
11
11
|
include Singleton
|
12
12
|
include MonitorMixin
|
13
13
|
|
14
|
-
#
|
15
|
-
# times in the Sidetiq schedules.
|
16
|
-
START_TIME = Sidetiq.config.utc ? Time.utc(2010, 1, 1) : Time.local(2010, 1, 1)
|
17
|
-
|
18
|
-
# Public: Returns a hash of Sidetiq::Schedule instances.
|
14
|
+
# Internal: Returns a hash of Sidetiq::Schedule instances.
|
19
15
|
attr_reader :schedules
|
20
16
|
|
21
|
-
#
|
17
|
+
# Internal: Returns the clock thread.
|
22
18
|
attr_reader :thread
|
23
19
|
|
24
20
|
def self.method_missing(meth, *args, &block) # :nodoc:
|
@@ -41,7 +37,7 @@ module Sidetiq
|
|
41
37
|
#
|
42
38
|
# Returns a Sidetiq::Schedule instances.
|
43
39
|
def schedule_for(worker)
|
44
|
-
schedules[worker] ||= Sidetiq::Schedule.new
|
40
|
+
schedules[worker] ||= Sidetiq::Schedule.new
|
45
41
|
end
|
46
42
|
|
47
43
|
# Public: Issue a single clock tick.
|
@@ -53,12 +49,18 @@ module Sidetiq
|
|
53
49
|
#
|
54
50
|
# Returns a hash of Sidetiq::Schedule instances.
|
55
51
|
def tick
|
56
|
-
|
52
|
+
tick = gettime
|
57
53
|
synchronize do
|
58
|
-
schedules.each do |worker,
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
schedules.each do |worker, sched|
|
55
|
+
synchronize_clockworks(worker) do |redis|
|
56
|
+
if sched.backfill? && (last = worker.last_scheduled_occurrence) > 0
|
57
|
+
last = Sidetiq.config.utc ? Time.at(last).utc : Time.at(last)
|
58
|
+
sched.occurrences_between(last + 1, tick).each do |past_t|
|
59
|
+
enqueue(worker, past_t, redis)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
enqueue(worker, sched.next_occurrence(tick), redis)
|
63
|
+
end if sched.schedule_next?(tick)
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -89,7 +91,8 @@ module Sidetiq
|
|
89
91
|
def start!
|
90
92
|
return if ticking?
|
91
93
|
|
92
|
-
|
94
|
+
Sidetiq.logger.info "Sidetiq::Clock start"
|
95
|
+
|
93
96
|
@thread = Thread.start { clock { tick } }
|
94
97
|
@thread.abort_on_exception = true
|
95
98
|
@thread.priority = Sidetiq.config.priority
|
@@ -107,7 +110,7 @@ module Sidetiq
|
|
107
110
|
def stop!
|
108
111
|
if ticking?
|
109
112
|
@thread.kill
|
110
|
-
|
113
|
+
Sidetiq.logger.info "Sidetiq::Clock stop"
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
@@ -129,36 +132,35 @@ module Sidetiq
|
|
129
132
|
|
130
133
|
private
|
131
134
|
|
132
|
-
def enqueue(worker, time)
|
133
|
-
key
|
134
|
-
time_f
|
135
|
-
|
136
|
-
synchronize_clockworks("#{key}:lock") do |redis|
|
137
|
-
next_run = (redis.get("#{key}:next") || -1).to_f
|
135
|
+
def enqueue(worker, time, redis)
|
136
|
+
key = "sidetiq:#{worker.name}"
|
137
|
+
time_f = time.to_f
|
138
|
+
next_run = (redis.get("#{key}:next") || -1).to_f
|
138
139
|
|
139
|
-
|
140
|
-
|
140
|
+
if next_run < time_f
|
141
|
+
Sidetiq.logger.info "Sidetiq::Clock enqueue #{worker.name} (at: #{time_f}) (last: #{next_run})"
|
141
142
|
|
142
|
-
|
143
|
+
redis.mset("#{key}:last", next_run, "#{key}:next", time_f)
|
143
144
|
|
144
|
-
|
145
|
-
|
145
|
+
arity = [worker.instance_method(:perform).arity - 1, -1].max
|
146
|
+
args = [next_run, time_f][0..arity]
|
146
147
|
|
147
|
-
|
148
|
-
end
|
148
|
+
worker.perform_at(time, *args)
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
-
def synchronize_clockworks(
|
152
|
+
def synchronize_clockworks(klass)
|
153
|
+
lock = "sidetiq:#{klass.name}:lock"
|
154
|
+
|
153
155
|
Sidekiq.redis do |redis|
|
154
156
|
if redis.setnx(lock, 1)
|
155
|
-
|
157
|
+
Sidetiq.logger.debug "Sidetiq::Clock lock #{lock}"
|
156
158
|
|
157
159
|
redis.pexpire(lock, Sidetiq.config.lock_expire)
|
158
160
|
yield redis
|
159
161
|
redis.del(lock)
|
160
162
|
|
161
|
-
|
163
|
+
Sidetiq.logger.debug "Sidetiq::Clock unlock #{lock}"
|
162
164
|
end
|
163
165
|
end
|
164
166
|
end
|
@@ -181,3 +183,4 @@ module Sidetiq
|
|
181
183
|
end
|
182
184
|
end
|
183
185
|
end
|
186
|
+
|
data/lib/sidetiq/middleware.rb
CHANGED
data/lib/sidetiq/schedulable.rb
CHANGED
@@ -4,30 +4,34 @@ module Sidetiq
|
|
4
4
|
# Examples
|
5
5
|
#
|
6
6
|
# class MyWorker
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# include Sidekiq::Worker
|
8
|
+
# include Sidetiq::Schedulable
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# # Daily at midnight
|
11
|
+
# tiq { daily }
|
12
|
+
# end
|
13
13
|
module Schedulable
|
14
14
|
module ClassMethods
|
15
|
+
# Public: Returns a Float timestamp of the last scheduled run.
|
15
16
|
def last_scheduled_occurrence
|
16
17
|
get_timestamp "last"
|
17
18
|
end
|
18
19
|
|
20
|
+
# Public: Returns a Float timestamp of the next scheduled run.
|
19
21
|
def next_scheduled_occurrence
|
20
22
|
get_timestamp "next"
|
21
23
|
end
|
22
24
|
|
23
|
-
def tiq(&block) # :nodoc:
|
25
|
+
def tiq(options = {}, &block) # :nodoc:
|
24
26
|
clock = Sidetiq::Clock.instance
|
25
27
|
clock.synchronize do
|
26
|
-
clock.schedule_for(self)
|
28
|
+
schedule = clock.schedule_for(self)
|
29
|
+
schedule.instance_eval(&block)
|
30
|
+
schedule.set_options(options)
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
30
|
-
|
34
|
+
private
|
31
35
|
|
32
36
|
def get_timestamp(key)
|
33
37
|
Sidekiq.redis do |redis|
|
@@ -41,3 +45,4 @@ module Sidetiq
|
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
48
|
+
|
data/lib/sidetiq/schedule.rb
CHANGED
@@ -1,23 +1,75 @@
|
|
1
1
|
module Sidetiq
|
2
|
-
#
|
3
|
-
class Schedule
|
4
|
-
|
2
|
+
# Public: Recurrence schedule.
|
3
|
+
class Schedule
|
4
|
+
# :nodoc:
|
5
|
+
attr_reader :last_occurrence
|
6
|
+
|
7
|
+
# Public: Writer for backfilling option.
|
8
|
+
attr_writer :backfill
|
9
|
+
|
10
|
+
# Public: Start time offset from epoch used for calculating run
|
11
|
+
# times in the Sidetiq schedules.
|
12
|
+
START_TIME = Sidetiq.config.utc ? Time.utc(2010, 1, 1) : Time.local(2010, 1, 1)
|
13
|
+
|
14
|
+
def initialize # :nodoc:
|
15
|
+
@schedule = IceCube::Schedule.new(START_TIME)
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(meth, *args, &block) # :nodoc:
|
5
19
|
if IceCube::Rule.respond_to?(meth)
|
6
20
|
rule = IceCube::Rule.send(meth, *args, &block)
|
7
|
-
add_recurrence_rule(rule)
|
21
|
+
@schedule.add_recurrence_rule(rule)
|
8
22
|
rule
|
23
|
+
elsif @schedule.respond_to?(meth)
|
24
|
+
@schedule.send(meth, *args, &block)
|
9
25
|
else
|
10
26
|
super
|
11
27
|
end
|
12
28
|
end
|
13
29
|
|
30
|
+
# Public: Checks if a job is due to be scheduled.
|
31
|
+
#
|
32
|
+
# Returns true if a job is due, otherwise false.
|
14
33
|
def schedule_next?(time)
|
15
|
-
|
16
|
-
|
34
|
+
next_occurrence = @schedule.next_occurrence(time)
|
35
|
+
if @last_scheduled != next_occurrence
|
36
|
+
@last_scheduled = next_occurrence
|
17
37
|
return true
|
18
38
|
end
|
19
39
|
false
|
20
40
|
end
|
41
|
+
|
42
|
+
# Public: Schedule to String.
|
43
|
+
#
|
44
|
+
# Examples
|
45
|
+
#
|
46
|
+
# class MyWorker
|
47
|
+
# include Sidekiq::Worker
|
48
|
+
# include Sidetiq::Schedulable
|
49
|
+
#
|
50
|
+
# tiq { daily }
|
51
|
+
#
|
52
|
+
# def perform
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# Sidetiq.schedules[MyWorker].to_s
|
57
|
+
# # => "Daily"
|
58
|
+
#
|
59
|
+
# Returns a String representing the schedule.
|
60
|
+
def to_s
|
61
|
+
@schedule.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
# Public: Inquirer for backfilling option.
|
65
|
+
def backfill?
|
66
|
+
!!@backfill
|
67
|
+
end
|
68
|
+
|
69
|
+
# Internal: Set schedule options.
|
70
|
+
def set_options(hash)
|
71
|
+
self.backfill = hash[:backfill] if !hash[:backfill].nil?
|
72
|
+
end
|
21
73
|
end
|
22
74
|
end
|
23
75
|
|
data/lib/sidetiq/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
class ScheduledWorker
|
2
|
+
include Sidekiq::Worker
|
3
|
+
include Sidetiq::Schedulable
|
4
|
+
|
5
|
+
tiq do
|
6
|
+
daily.hour_of_day(1)
|
7
|
+
yearly.month_of_year(2)
|
8
|
+
monthly.day_of_month(3)
|
9
|
+
|
10
|
+
add_exception_rule yearly.month_of_year(:february)
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
data/test/helper.rb
CHANGED
@@ -13,8 +13,12 @@ require 'sidekiq/testing'
|
|
13
13
|
require 'sidetiq'
|
14
14
|
require 'sidetiq/web'
|
15
15
|
|
16
|
-
# Keep the test output clean
|
17
|
-
|
16
|
+
# Keep the test output clean.
|
17
|
+
Sidetiq.logger = Logger.new(nil)
|
18
|
+
|
19
|
+
Dir[File.join(File.dirname(__FILE__), 'fixtures/**/*.rb')].each do |fixture|
|
20
|
+
require fixture
|
21
|
+
end
|
18
22
|
|
19
23
|
class Sidetiq::TestCase < MiniTest::Unit::TestCase
|
20
24
|
def setup
|
@@ -24,5 +28,16 @@ class Sidetiq::TestCase < MiniTest::Unit::TestCase
|
|
24
28
|
def clock
|
25
29
|
@clock ||= Sidetiq::Clock.instance
|
26
30
|
end
|
31
|
+
|
32
|
+
# Blatantly stolen from Sidekiq's test suite.
|
33
|
+
def add_retry(worker = 'SimpleWorker', jid = 'bob', at = Time.now.to_f)
|
34
|
+
payload = Sidekiq.dump_json('class' => worker,
|
35
|
+
'args' => [], 'queue' => 'default', 'jid' => jid,
|
36
|
+
'retry_count' => 2, 'failed_at' => Time.now.utc)
|
37
|
+
|
38
|
+
Sidekiq.redis do |conn|
|
39
|
+
conn.zadd('retry', at.to_s, payload)
|
40
|
+
end
|
41
|
+
end
|
27
42
|
end
|
28
43
|
|
data/test/test_clock.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
class TestClock < Sidetiq::TestCase
|
4
|
-
class FakeWorker
|
5
|
-
def perform
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
4
|
def test_delegates_to_instance
|
10
5
|
Sidetiq::Clock.instance.expects(:foo).once
|
11
6
|
Sidetiq::Clock.foo
|
@@ -45,13 +40,28 @@ class TestClock < Sidetiq::TestCase
|
|
45
40
|
Sidetiq.config.utc = false
|
46
41
|
end
|
47
42
|
|
43
|
+
def test_backfilling
|
44
|
+
BackfillWorker.jobs.clear
|
45
|
+
start = Sidetiq::Schedule::START_TIME
|
46
|
+
|
47
|
+
BackfillWorker.stubs(:last_scheduled_occurrence).returns(start.to_f)
|
48
|
+
clock.stubs(:gettime).returns(start)
|
49
|
+
clock.tick
|
50
|
+
|
51
|
+
BackfillWorker.jobs.clear
|
52
|
+
|
53
|
+
clock.stubs(:gettime).returns(start + 86400 * 10 + 1)
|
54
|
+
clock.tick
|
55
|
+
assert_equal 10, BackfillWorker.jobs.length
|
56
|
+
end
|
57
|
+
|
48
58
|
def test_enqueues_jobs_by_schedule
|
49
|
-
schedule = Sidetiq::Schedule.new
|
59
|
+
schedule = Sidetiq::Schedule.new
|
50
60
|
schedule.daily
|
51
61
|
|
52
|
-
clock.stubs(:schedules).returns(
|
62
|
+
clock.stubs(:schedules).returns(SimpleWorker => schedule)
|
53
63
|
|
54
|
-
|
64
|
+
SimpleWorker.expects(:perform_at).times(10)
|
55
65
|
|
56
66
|
10.times do |i|
|
57
67
|
clock.stubs(:gettime).returns(Time.local(2011, 1, i + 1, 1))
|
@@ -64,13 +74,8 @@ class TestClock < Sidetiq::TestCase
|
|
64
74
|
clock.tick
|
65
75
|
end
|
66
76
|
|
67
|
-
class LastTickWorker
|
68
|
-
def perform last_tick
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
77
|
def test_enqueues_jobs_with_default_last_tick_arg_on_first_run
|
73
|
-
schedule = Sidetiq::Schedule.new
|
78
|
+
schedule = Sidetiq::Schedule.new
|
74
79
|
schedule.hourly
|
75
80
|
|
76
81
|
time = Time.local(2011, 1, 1, 1, 30)
|
@@ -82,19 +87,15 @@ class TestClock < Sidetiq::TestCase
|
|
82
87
|
expected_second_tick = expected_first_tick + 3600
|
83
88
|
|
84
89
|
LastTickWorker.expects(:perform_at).with(expected_first_tick, -1).once
|
85
|
-
LastTickWorker.expects(:perform_at).with(expected_second_tick,
|
90
|
+
LastTickWorker.expects(:perform_at).with(expected_second_tick,
|
91
|
+
expected_first_tick.to_f).once
|
86
92
|
|
87
93
|
clock.tick
|
88
94
|
clock.tick
|
89
95
|
end
|
90
96
|
|
91
|
-
class LastAndScheduledTicksWorker
|
92
|
-
def perform last_tick, scheduled_tick
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
97
|
def test_enqueues_jobs_with_last_run_timestamp_and_next_run_timestamp
|
97
|
-
schedule = Sidetiq::Schedule.new
|
98
|
+
schedule = Sidetiq::Schedule.new
|
98
99
|
schedule.hourly
|
99
100
|
|
100
101
|
time = Time.local(2011, 1, 1, 1, 30)
|
@@ -105,20 +106,20 @@ class TestClock < Sidetiq::TestCase
|
|
105
106
|
expected_first_tick = time + 1800
|
106
107
|
expected_second_tick = expected_first_tick + 3600
|
107
108
|
|
108
|
-
LastAndScheduledTicksWorker.expects(:perform_at)
|
109
|
-
|
109
|
+
LastAndScheduledTicksWorker.expects(:perform_at)
|
110
|
+
.with(expected_first_tick, -1, expected_first_tick.to_f).once
|
110
111
|
|
111
|
-
LastAndScheduledTicksWorker.expects(:perform_at).with(expected_second_tick, expected_first_tick.to_f, expected_second_tick.to_f).once
|
112
112
|
clock.tick
|
113
|
-
end
|
114
113
|
|
115
|
-
|
116
|
-
|
117
|
-
|
114
|
+
LastAndScheduledTicksWorker.expects(:perform_at)
|
115
|
+
.with(expected_second_tick, expected_first_tick.to_f,
|
116
|
+
expected_second_tick.to_f).once
|
117
|
+
|
118
|
+
clock.tick
|
118
119
|
end
|
119
120
|
|
120
121
|
def test_enqueues_jobs_correctly_for_splat_args_perform_methods
|
121
|
-
schedule = Sidetiq::Schedule.new
|
122
|
+
schedule = Sidetiq::Schedule.new
|
122
123
|
schedule.hourly
|
123
124
|
|
124
125
|
time = Time.local(2011, 1, 1, 1, 30)
|
@@ -128,7 +129,8 @@ class TestClock < Sidetiq::TestCase
|
|
128
129
|
|
129
130
|
expected_first_tick = time + 1800
|
130
131
|
|
131
|
-
SplatArgsWorker.expects(:perform_at)
|
132
|
+
SplatArgsWorker.expects(:perform_at)
|
133
|
+
.with(expected_first_tick, -1, expected_first_tick.to_f).once
|
132
134
|
clock.tick
|
133
135
|
end
|
134
136
|
end
|
data/test/test_schedule.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
class TestSchedule < Sidetiq::TestCase
|
4
|
-
def test_super
|
5
|
-
assert_equal IceCube::Schedule, Sidetiq::Schedule.superclass
|
6
|
-
end
|
7
|
-
|
8
4
|
def test_method_missing
|
9
5
|
sched = Sidetiq::Schedule.new
|
10
6
|
sched.daily
|
@@ -21,5 +17,22 @@ class TestSchedule < Sidetiq::TestCase
|
|
21
17
|
assert sched.schedule_next?(Time.now + (2 * 24 * 60 * 60))
|
22
18
|
refute sched.schedule_next?(Time.now + (2 * 24 * 60 * 60))
|
23
19
|
end
|
20
|
+
|
21
|
+
def test_backfill
|
22
|
+
sched = Sidetiq::Schedule.new
|
23
|
+
refute sched.backfill?
|
24
|
+
sched.backfill = true
|
25
|
+
assert sched.backfill?
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_set_options
|
29
|
+
sched = Sidetiq::Schedule.new
|
30
|
+
|
31
|
+
sched.set_options(backfill: true)
|
32
|
+
assert sched.backfill?
|
33
|
+
|
34
|
+
sched.set_options(backfill: false)
|
35
|
+
refute sched.backfill?
|
36
|
+
end
|
24
37
|
end
|
25
38
|
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class TestSidetiq < Sidetiq::TestCase
|
4
|
+
def test_schedules
|
5
|
+
schedules = Sidetiq.schedules
|
6
|
+
|
7
|
+
assert_equal 2, schedules.length
|
8
|
+
|
9
|
+
assert_includes schedules.keys, ScheduledWorker
|
10
|
+
assert_includes schedules.keys, BackfillWorker
|
11
|
+
|
12
|
+
assert_kind_of Sidetiq::Schedule, schedules[ScheduledWorker]
|
13
|
+
assert_kind_of Sidetiq::Schedule, schedules[BackfillWorker]
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_workers
|
17
|
+
workers = Sidetiq.workers
|
18
|
+
|
19
|
+
assert_includes workers, ScheduledWorker
|
20
|
+
assert_includes workers, BackfillWorker
|
21
|
+
assert_equal 2, workers.length
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_scheduled
|
25
|
+
SimpleWorker.perform_at(Time.local(2011, 1, 1, 1))
|
26
|
+
SimpleWorker.client_push_old(SimpleWorker.jobs.first)
|
27
|
+
|
28
|
+
scheduled = Sidetiq.scheduled
|
29
|
+
|
30
|
+
assert_kind_of Array, scheduled
|
31
|
+
assert_kind_of Sidekiq::SortedEntry, scheduled.first
|
32
|
+
assert_equal 1, scheduled.length
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_scheduled_on_empty_set
|
36
|
+
assert_equal 0, Sidetiq.scheduled.length
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_scheduled_given_arguments
|
40
|
+
SimpleWorker.perform_at(Time.local(2011, 1, 1, 1))
|
41
|
+
SimpleWorker.client_push_old(SimpleWorker.jobs.first)
|
42
|
+
|
43
|
+
assert_equal 1, Sidetiq.scheduled(SimpleWorker).length
|
44
|
+
assert_equal 0, Sidetiq.scheduled(ScheduledWorker).length
|
45
|
+
|
46
|
+
assert_equal 1, Sidetiq.scheduled("SimpleWorker").length
|
47
|
+
assert_equal 0, Sidetiq.scheduled("ScheduledWorker").length
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_scheduled_yields_each_job
|
51
|
+
SimpleWorker.perform_at(Time.local(2011, 1, 1, 1))
|
52
|
+
SimpleWorker.client_push_old(SimpleWorker.jobs.first)
|
53
|
+
|
54
|
+
ScheduledWorker.perform_at(Time.local(2011, 1, 1, 1))
|
55
|
+
ScheduledWorker.client_push_old(ScheduledWorker.jobs.first)
|
56
|
+
|
57
|
+
jobs = []
|
58
|
+
Sidetiq.scheduled { |job| jobs << job }
|
59
|
+
assert_equal 2, jobs.length
|
60
|
+
|
61
|
+
jobs = []
|
62
|
+
Sidetiq.scheduled(SimpleWorker) { |job| jobs << job }
|
63
|
+
assert_equal 1, jobs.length
|
64
|
+
|
65
|
+
jobs = []
|
66
|
+
Sidetiq.scheduled("ScheduledWorker") { |job| jobs << job }
|
67
|
+
assert_equal 1, jobs.length
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_scheduled_with_invalid_class
|
71
|
+
assert_raises(NameError) do
|
72
|
+
Sidetiq.scheduled("Foobar")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_retries
|
77
|
+
add_retry('SimpleWorker', 'foo')
|
78
|
+
add_retry('ScheduledWorker', 'bar')
|
79
|
+
|
80
|
+
retries = Sidetiq.retries
|
81
|
+
|
82
|
+
assert_kind_of Array, retries
|
83
|
+
assert_kind_of Sidekiq::SortedEntry, retries[0]
|
84
|
+
assert_kind_of Sidekiq::SortedEntry, retries[1]
|
85
|
+
assert_equal 2, retries.length
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_retries_on_empty_set
|
89
|
+
assert_equal 0, Sidetiq.retries.length
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_retries_given_arguments
|
93
|
+
add_retry('SimpleWorker', 'foo')
|
94
|
+
|
95
|
+
assert_equal 1, Sidetiq.retries(SimpleWorker).length
|
96
|
+
assert_equal 0, Sidetiq.retries(ScheduledWorker).length
|
97
|
+
|
98
|
+
assert_equal 1, Sidetiq.retries("SimpleWorker").length
|
99
|
+
assert_equal 0, Sidetiq.retries("ScheduledWorker").length
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_retries_yields_each_job
|
103
|
+
add_retry('SimpleWorker', 'foo')
|
104
|
+
add_retry('ScheduledWorker', 'foo')
|
105
|
+
|
106
|
+
jobs = []
|
107
|
+
Sidetiq.retries { |job| jobs << job }
|
108
|
+
assert_equal 2, jobs.length
|
109
|
+
|
110
|
+
jobs = []
|
111
|
+
Sidetiq.retries(SimpleWorker) { |job| jobs << job }
|
112
|
+
assert_equal 1, jobs.length
|
113
|
+
|
114
|
+
jobs = []
|
115
|
+
Sidetiq.retries("ScheduledWorker") { |job| jobs << job }
|
116
|
+
assert_equal 1, jobs.length
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_retries_with_invalid_class
|
120
|
+
assert_raises(NameError) do
|
121
|
+
Sidetiq.retries("Foobar")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
data/test/test_web.rb
CHANGED
@@ -3,19 +3,6 @@ require_relative 'helper'
|
|
3
3
|
class TestWeb < Sidetiq::TestCase
|
4
4
|
include Rack::Test::Methods
|
5
5
|
|
6
|
-
class Worker
|
7
|
-
include Sidekiq::Worker
|
8
|
-
include Sidetiq::Schedulable
|
9
|
-
|
10
|
-
tiq do
|
11
|
-
daily(1)
|
12
|
-
yearly(2)
|
13
|
-
monthly(3)
|
14
|
-
|
15
|
-
add_exception_rule yearly.month_of_year(:february)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
6
|
def app
|
20
7
|
Sidekiq::Web
|
21
8
|
end
|
@@ -26,7 +13,7 @@ class TestWeb < Sidetiq::TestCase
|
|
26
13
|
|
27
14
|
def setup
|
28
15
|
super
|
29
|
-
|
16
|
+
ScheduledWorker.jobs.clear
|
30
17
|
end
|
31
18
|
|
32
19
|
def test_home_tab
|
@@ -47,9 +34,9 @@ class TestWeb < Sidetiq::TestCase
|
|
47
34
|
end
|
48
35
|
|
49
36
|
def test_details_page
|
50
|
-
get "/sidetiq
|
37
|
+
get "/sidetiq/ScheduledWorker"
|
51
38
|
assert_equal 200, last_response.status
|
52
|
-
schedule = clock.schedules[
|
39
|
+
schedule = clock.schedules[ScheduledWorker]
|
53
40
|
|
54
41
|
schedule.recurrence_rules.each do |rule|
|
55
42
|
assert_match /#{rule.to_s}/, last_response.body
|
@@ -65,10 +52,10 @@ class TestWeb < Sidetiq::TestCase
|
|
65
52
|
end
|
66
53
|
|
67
54
|
def test_trigger
|
68
|
-
post "/sidetiq
|
55
|
+
post "/sidetiq/ScheduledWorker/trigger"
|
69
56
|
assert_equal 302, last_response.status
|
70
57
|
assert_equal "http://#{host}/sidetiq", last_response.location
|
71
|
-
assert_equal 1,
|
58
|
+
assert_equal 1, ScheduledWorker.jobs.size
|
72
59
|
end
|
73
60
|
end
|
74
61
|
|
data/test/test_worker.rb
CHANGED
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: sidetiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.3.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tobias Svensson
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -73,12 +73,19 @@ files:
|
|
73
73
|
- lib/sidetiq/views/sidetiq_details.slim
|
74
74
|
- lib/sidetiq/web.rb
|
75
75
|
- sidetiq.gemspec
|
76
|
+
- test/fixtures/backfill_worker.rb
|
77
|
+
- test/fixtures/last_and_scheduled_ticks_worker.rb
|
78
|
+
- test/fixtures/last_tick_worker.rb
|
79
|
+
- test/fixtures/scheduled_worker.rb
|
80
|
+
- test/fixtures/simple_worker.rb
|
81
|
+
- test/fixtures/splat_args_worker.rb
|
76
82
|
- test/helper.rb
|
77
83
|
- test/test_clock.rb
|
78
84
|
- test/test_config.rb
|
79
85
|
- test/test_errors.rb
|
80
86
|
- test/test_middleware.rb
|
81
87
|
- test/test_schedule.rb
|
88
|
+
- test/test_sidetiq.rb
|
82
89
|
- test/test_version.rb
|
83
90
|
- test/test_web.rb
|
84
91
|
- test/test_worker.rb
|
@@ -108,12 +115,19 @@ signing_key:
|
|
108
115
|
specification_version: 3
|
109
116
|
summary: Recurring jobs for Sidekiq
|
110
117
|
test_files:
|
118
|
+
- test/fixtures/backfill_worker.rb
|
119
|
+
- test/fixtures/last_and_scheduled_ticks_worker.rb
|
120
|
+
- test/fixtures/last_tick_worker.rb
|
121
|
+
- test/fixtures/scheduled_worker.rb
|
122
|
+
- test/fixtures/simple_worker.rb
|
123
|
+
- test/fixtures/splat_args_worker.rb
|
111
124
|
- test/helper.rb
|
112
125
|
- test/test_clock.rb
|
113
126
|
- test/test_config.rb
|
114
127
|
- test/test_errors.rb
|
115
128
|
- test/test_middleware.rb
|
116
129
|
- test/test_schedule.rb
|
130
|
+
- test/test_sidetiq.rb
|
117
131
|
- test/test_version.rb
|
118
132
|
- test/test_web.rb
|
119
133
|
- test/test_worker.rb
|