resque-scheduler 2.5.1 → 4.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +12 -0
- data/.github/funding.yml +4 -0
- data/.github/workflows/codeql-analysis.yml +59 -0
- data/.github/workflows/rubocop.yml +27 -0
- data/.github/workflows/ruby.yml +81 -0
- data/AUTHORS.md +25 -0
- data/CHANGELOG.md +539 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +26 -2
- data/README.md +291 -70
- data/Rakefile +8 -19
- data/exe/resque-scheduler +5 -0
- data/lib/resque/scheduler/cli.rb +147 -0
- data/lib/resque/scheduler/configuration.rb +102 -0
- data/lib/resque/scheduler/delaying_extensions.rb +371 -0
- data/lib/resque/scheduler/env.rb +85 -0
- data/lib/resque/scheduler/extension.rb +13 -0
- data/lib/resque/scheduler/failure_handler.rb +11 -0
- data/lib/resque/scheduler/lock/base.rb +13 -4
- data/lib/resque/scheduler/lock/basic.rb +4 -5
- data/lib/resque/scheduler/lock/resilient.rb +52 -43
- data/lib/resque/scheduler/lock.rb +2 -1
- data/lib/resque/scheduler/locking.rb +104 -0
- data/lib/resque/scheduler/logger_builder.rb +83 -0
- data/lib/resque/scheduler/plugin.rb +31 -0
- data/lib/resque/scheduler/scheduling_extensions.rb +142 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed.erb +21 -12
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed_schedules.erb +1 -1
- data/lib/{resque_scheduler → resque/scheduler}/server/views/delayed_timestamp.erb +1 -1
- data/lib/resque/scheduler/server/views/scheduler.erb +58 -0
- data/lib/{resque_scheduler → resque/scheduler}/server/views/search.erb +4 -7
- data/lib/{resque_scheduler → resque/scheduler}/server/views/search_form.erb +1 -5
- data/lib/resque/scheduler/server.rb +268 -0
- data/lib/resque/scheduler/signal_handling.rb +40 -0
- data/lib/{resque_scheduler → resque/scheduler}/tasks.rb +3 -6
- data/lib/resque/scheduler/util.rb +39 -0
- data/lib/resque/scheduler/version.rb +7 -0
- data/lib/resque/scheduler.rb +271 -199
- data/lib/resque-scheduler.rb +3 -1
- data/resque-scheduler.gemspec +53 -20
- metadata +176 -132
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -129
- data/.simplecov +0 -1
- data/.travis.yml +0 -21
- data/HISTORY.md +0 -226
- data/ROADMAP.md +0 -10
- data/bin/resque-scheduler +0 -5
- data/examples/Rakefile +0 -2
- data/examples/config/initializers/resque-web.rb +0 -37
- data/examples/dynamic-scheduling/README.md +0 -28
- data/examples/dynamic-scheduling/app/jobs/fix_schedules_job.rb +0 -54
- data/examples/dynamic-scheduling/app/jobs/send_email_job.rb +0 -9
- data/examples/dynamic-scheduling/app/models/user.rb +0 -16
- data/examples/dynamic-scheduling/config/resque.yml +0 -4
- data/examples/dynamic-scheduling/config/static_schedule.yml +0 -7
- data/examples/dynamic-scheduling/lib/tasks/resque.rake +0 -48
- data/examples/run-resque-web +0 -3
- data/lib/resque/scheduler_locking.rb +0 -91
- data/lib/resque_scheduler/cli.rb +0 -160
- data/lib/resque_scheduler/logger_builder.rb +0 -70
- data/lib/resque_scheduler/plugin.rb +0 -28
- data/lib/resque_scheduler/server/views/scheduler.erb +0 -36
- data/lib/resque_scheduler/server.rb +0 -182
- data/lib/resque_scheduler/util.rb +0 -34
- data/lib/resque_scheduler/version.rb +0 -5
- data/lib/resque_scheduler.rb +0 -386
- data/script/migrate_to_timestamps_set.rb +0 -14
- data/tasks/resque_scheduler.rake +0 -2
- data/test/cli_test.rb +0 -286
- data/test/delayed_queue_test.rb +0 -449
- data/test/redis-test.conf +0 -108
- data/test/resque-web_test.rb +0 -199
- data/test/scheduler_args_test.rb +0 -190
- data/test/scheduler_hooks_test.rb +0 -23
- data/test/scheduler_locking_test.rb +0 -242
- data/test/scheduler_setup_test.rb +0 -95
- data/test/scheduler_task_test.rb +0 -35
- data/test/scheduler_test.rb +0 -344
- data/test/support/redis_instance.rb +0 -134
- data/test/test_helper.rb +0 -131
- /data/lib/{resque_scheduler → resque/scheduler}/server/views/requeue-params.erb +0 -0
data/README.md
CHANGED
@@ -1,24 +1,17 @@
|
|
1
1
|
resque-scheduler
|
2
2
|
================
|
3
3
|
|
4
|
-
|
5
|
-
[![Gem Version](https://badge.fury.io/rb/resque-scheduler.
|
6
|
-
[![
|
4
|
+
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/resque-scheduler.svg)](https://badge.fury.io/rb/resque-scheduler)
|
6
|
+
[![Ruby specs](https://github.com/resque/resque-scheduler/actions/workflows/ruby.yml/badge.svg)](https://github.com/resque/resque-scheduler/actions)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/resque/resque-scheduler/badges/gpa.svg)](https://codeclimate.com/github/resque/resque-scheduler)
|
7
8
|
|
8
9
|
### Description
|
9
10
|
|
10
11
|
Resque-scheduler is an extension to [Resque](http://github.com/resque/resque)
|
11
12
|
that adds support for queueing items in the future.
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
| resque-scheduler version | required redis gem version|
|
16
|
-
|:-------------------------|----------------------:|
|
17
|
-
| ~> 2.0 | >= 3.0.0 |
|
18
|
-
| >= 0.0.1 | ~> 1.3 |
|
19
|
-
|
20
|
-
|
21
|
-
Job scheduling is supported in two different way: Recurring (scheduled) and
|
14
|
+
Job scheduling is supported in two different ways: Recurring (scheduled) and
|
22
15
|
Delayed.
|
23
16
|
|
24
17
|
Scheduled jobs are like cron jobs, recurring on a regular basis. Delayed
|
@@ -26,9 +19,9 @@ jobs are resque jobs that you want to run at some point in the future.
|
|
26
19
|
The syntax is pretty explanatory:
|
27
20
|
|
28
21
|
```ruby
|
29
|
-
Resque.enqueue_in(5.days, SendFollowupEmail) #
|
22
|
+
Resque.enqueue_in(5.days, SendFollowupEmail, argument) # runs a job in 5 days, calling SendFollowupEmail.perform(argument)
|
30
23
|
# or
|
31
|
-
Resque.enqueue_at(5.days.from_now, SomeJob) #
|
24
|
+
Resque.enqueue_at(5.days.from_now, SomeJob, argument) # runs a job at a specific time, calling SomeJob.perform(argument)
|
32
25
|
```
|
33
26
|
|
34
27
|
### Documentation
|
@@ -43,7 +36,7 @@ To install:
|
|
43
36
|
|
44
37
|
gem install resque-scheduler
|
45
38
|
|
46
|
-
If you use a Gemfile
|
39
|
+
If you use a Gemfile:
|
47
40
|
|
48
41
|
```ruby
|
49
42
|
gem 'resque-scheduler'
|
@@ -52,29 +45,31 @@ gem 'resque-scheduler'
|
|
52
45
|
Adding the resque:scheduler rake task:
|
53
46
|
|
54
47
|
```ruby
|
55
|
-
require '
|
48
|
+
require 'resque/scheduler/tasks'
|
56
49
|
```
|
57
50
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
`resque
|
64
|
-
to know.
|
51
|
+
### Rake integration
|
52
|
+
|
53
|
+
By default, `resque-scheduler` depends on the "resque:setup" rake task.
|
54
|
+
Since you probably already have this task, lets just put our
|
55
|
+
configuration there. `resque-scheduler` pretty much needs to know
|
56
|
+
everything `resque` needs to know.
|
65
57
|
|
66
58
|
```ruby
|
67
59
|
# Resque tasks
|
68
60
|
require 'resque/tasks'
|
69
|
-
require '
|
61
|
+
require 'resque/scheduler/tasks'
|
70
62
|
|
71
63
|
namespace :resque do
|
72
64
|
task :setup do
|
73
65
|
require 'resque'
|
74
|
-
require 'resque_scheduler'
|
75
66
|
|
76
67
|
# you probably already have this somewhere
|
77
68
|
Resque.redis = 'localhost:6379'
|
69
|
+
end
|
70
|
+
|
71
|
+
task :setup_schedule => :setup do
|
72
|
+
require 'resque-scheduler'
|
78
73
|
|
79
74
|
# If you want to be able to dynamically change the schedule,
|
80
75
|
# uncomment this line. A dynamic schedule can be updated via the
|
@@ -82,7 +77,7 @@ namespace :resque do
|
|
82
77
|
# When dynamic is set to true, the scheduler process looks for
|
83
78
|
# schedule changes and applies them on the fly.
|
84
79
|
# Note: This feature is only available in >=2.0.0.
|
85
|
-
#Resque::Scheduler.dynamic = true
|
80
|
+
# Resque::Scheduler.dynamic = true
|
86
81
|
|
87
82
|
# The schedule doesn't need to be stored in a YAML, it just needs to
|
88
83
|
# be a hash. YAML is usually the easiest.
|
@@ -95,26 +90,65 @@ namespace :resque do
|
|
95
90
|
# So, something like this:
|
96
91
|
require 'jobs'
|
97
92
|
end
|
93
|
+
|
94
|
+
task :scheduler => :setup_schedule
|
98
95
|
end
|
99
96
|
```
|
100
97
|
|
101
|
-
The scheduler
|
102
|
-
|
103
|
-
|
104
|
-
never exits.
|
98
|
+
The scheduler rake task is responsible for both queueing items from the
|
99
|
+
schedule and polling the delayed queue for items ready to be pushed on
|
100
|
+
to the work queues. For obvious reasons, this process never exits.
|
105
101
|
|
106
|
-
|
102
|
+
``` bash
|
103
|
+
rake resque:scheduler
|
104
|
+
```
|
107
105
|
|
108
106
|
or, if you want to load the environment first:
|
109
107
|
|
110
|
-
|
108
|
+
``` bash
|
109
|
+
rake environment resque:scheduler
|
110
|
+
```
|
111
|
+
|
111
112
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
### Standalone Executable
|
114
|
+
|
115
|
+
The scheduler may also be run via a standalone `resque-scheduler`
|
116
|
+
executable, which will be available once the gem is installed.
|
117
|
+
|
118
|
+
``` bash
|
119
|
+
# Get some help
|
120
|
+
resque-scheduler --help
|
121
|
+
```
|
116
122
|
|
117
|
-
|
123
|
+
The executable accepts options via option flags as well as via
|
124
|
+
[environment variables](#environment-variables).
|
125
|
+
|
126
|
+
### Environment Variables
|
127
|
+
|
128
|
+
Both the Rake task and standalone executable support the following
|
129
|
+
environment variables:
|
130
|
+
|
131
|
+
* `APP_NAME` - Application name used in procline (`$0`) (default empty)
|
132
|
+
* `BACKGROUND` - [Run in the background](#running-in-the-background) if
|
133
|
+
non-empty (via `Process.daemon`, if supported) (default `false`)
|
134
|
+
* `DYNAMIC_SCHEDULE` - Enables [dynamic scheduling](#dynamic-schedules)
|
135
|
+
if non-empty (default `false`)
|
136
|
+
* `RAILS_ENV` - Environment to use in procline (`$0`) (default empty)
|
137
|
+
* `INITIALIZER_PATH` - Path to a Ruby file that will be loaded *before*
|
138
|
+
requiring `resque` and `resque/scheduler` (default empty).
|
139
|
+
* `RESQUE_SCHEDULER_INTERVAL` - Interval in seconds for checking if a
|
140
|
+
scheduled job must run (coerced with `Kernel#Float()`) (default `5`)
|
141
|
+
* `LOGFILE` - Log file name (default empty, meaning `$stdout`)
|
142
|
+
* `LOGFORMAT` - Log output format to use (either `'text'`, `'json'` or `'logfmt'`,
|
143
|
+
default `'text'`)
|
144
|
+
* `PIDFILE` - If non-empty, write process PID to file (default empty)
|
145
|
+
* `QUIET` - Silence most output if non-empty (equivalent to a level of
|
146
|
+
`MonoLogger::FATAL`, default `false`)
|
147
|
+
* `VERBOSE` - Maximize log verbosity if non-empty (equivalent to a level
|
148
|
+
of `MonoLogger::DEBUG`, default `false`)
|
149
|
+
|
150
|
+
|
151
|
+
### Resque Pool integration
|
118
152
|
|
119
153
|
For normal work with the
|
120
154
|
[resque-pool](https://github.com/nevans/resque-pool) gem, add the
|
@@ -124,7 +158,7 @@ following task to wherever tasks are kept, such as
|
|
124
158
|
```ruby
|
125
159
|
task 'resque:pool:setup' do
|
126
160
|
Resque::Pool.after_prefork do |job|
|
127
|
-
Resque.redis.
|
161
|
+
Resque.redis.reconnect
|
128
162
|
end
|
129
163
|
end
|
130
164
|
```
|
@@ -136,7 +170,11 @@ Delayed jobs are one-off jobs that you want to be put into a queue at some point
|
|
136
170
|
in the future. The classic example is sending email:
|
137
171
|
|
138
172
|
```ruby
|
139
|
-
Resque.enqueue_in(
|
173
|
+
Resque.enqueue_in(
|
174
|
+
5.days,
|
175
|
+
SendFollowUpEmail,
|
176
|
+
user_id: current_user.id
|
177
|
+
)
|
140
178
|
```
|
141
179
|
|
142
180
|
This will store the job for 5 days in the resque delayed queue at which time
|
@@ -144,13 +182,22 @@ the scheduler process will pull it from the delayed queue and put it in the
|
|
144
182
|
appropriate work queue for the given job and it will be processed as soon as
|
145
183
|
a worker is available (just like any other resque job).
|
146
184
|
|
147
|
-
NOTE
|
185
|
+
**NOTE**: The job does not fire **exactly** at the time supplied. Rather, once that
|
148
186
|
time is in the past, the job moves from the delayed queue to the actual resque
|
149
|
-
work queue and will be completed as workers
|
187
|
+
work queue and will be completed as workers are free to process it.
|
150
188
|
|
151
189
|
Also supported is `Resque.enqueue_at` which takes a timestamp to queue the
|
152
190
|
job, and `Resque.enqueue_at_with_queue` which takes both a timestamp and a
|
153
|
-
queue name
|
191
|
+
queue name:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
Resque.enqueue_at_with_queue(
|
195
|
+
'queue_name',
|
196
|
+
5.days.from_now,
|
197
|
+
SendFollowUpEmail,
|
198
|
+
user_id: current_user.id
|
199
|
+
)
|
200
|
+
```
|
154
201
|
|
155
202
|
The delayed queue is stored in redis and is persisted in the same way the
|
156
203
|
standard resque jobs are persisted (redis writing to disk). Delayed jobs differ
|
@@ -164,7 +211,7 @@ since the jobs are stored in a redis sorted set (zset). I can't imagine this
|
|
164
211
|
being an issue for someone since redis is stupidly fast even at log(n), but full
|
165
212
|
disclosure is always best.
|
166
213
|
|
167
|
-
#### Removing Delayed
|
214
|
+
#### Removing Delayed Jobs
|
168
215
|
|
169
216
|
If you have the need to cancel a delayed job, you can do like so:
|
170
217
|
|
@@ -186,6 +233,71 @@ Resque.remove_delayed_selection { |args| args[0]['account_id'] == current_accoun
|
|
186
233
|
Resque.remove_delayed_selection { |args| args[0]['user_id'] == current_user.id }
|
187
234
|
```
|
188
235
|
|
236
|
+
If you need to cancel a delayed job based on some matching arguments AND by which class the job is, but don't wish to specify each argument from when the job was created, you can do like so:
|
237
|
+
|
238
|
+
``` ruby
|
239
|
+
# after you've enqueued a job like:
|
240
|
+
Resque.enqueue_at(5.days.from_now, SendFollowUpEmail, :account_id => current_account.id, :user_id => current_user.id)
|
241
|
+
# remove jobs matching just the account and that were of the class SendFollowUpEmail:
|
242
|
+
Resque.remove_delayed_selection(SendFollowUpEmail) { |args| args[0]['account_id'] == current_account.id }
|
243
|
+
# or remove jobs matching just the user and that were of the class SendFollowUpEmail:
|
244
|
+
Resque.remove_delayed_selection(SendFollowUpEmail) { |args| args[0]['user_id'] == current_user.id }
|
245
|
+
```
|
246
|
+
|
247
|
+
If you need to enqueue immediately a delayed job based on some matching arguments, but don't wish to specify each argument from when the job was created, you can do like so:
|
248
|
+
|
249
|
+
``` ruby
|
250
|
+
# after you've enqueued a job like:
|
251
|
+
Resque.enqueue_at(5.days.from_now, SendFollowUpEmail, :account_id => current_account.id, :user_id => current_user.id)
|
252
|
+
# enqueue immediately jobs matching just the account:
|
253
|
+
Resque.enqueue_delayed_selection { |args| args[0]['account_id'] == current_account.id }
|
254
|
+
# or enqueue immediately jobs matching just the user:
|
255
|
+
Resque.enqueue_delayed_selection { |args| args[0]['user_id'] == current_user.id }
|
256
|
+
```
|
257
|
+
|
258
|
+
#### Updating Delayed Jobs
|
259
|
+
|
260
|
+
Previously delayed jobs may be delayed even further into the future like so:
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
# after you've enqueued a job like:
|
264
|
+
Resque.enqueue_at(1.minute.from_now, SendNotifications, :user_id => current_user.id)
|
265
|
+
# delay running the job until two minutes from now
|
266
|
+
Resque.delay_or_enqueue_at(2.minutes.from_now, SendNotifications, :user_id => current_user.id)
|
267
|
+
```
|
268
|
+
|
269
|
+
You don't need to worry if a matching job has already been queued, because if no matching jobs are found a new job is created and enqueued as if you had called `enqueue_at`. This means you don't need any special conditionals to know if a job has already been queued. You simply create the job like so:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
Resque.delay_or_enqueue_at(1.minute.from_now, SendNotifications, :user_id => current_user.id)
|
273
|
+
```
|
274
|
+
|
275
|
+
If multiple matching jobs are found, all of the matching jobs will be updated to have the same timestamp even if their original timestamps were not the same.
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
# enqueue multiple jobs with different delay timestamps
|
279
|
+
Resque.enqueue_at(1.minute.from_now, SendNotifications, :user_id => current_user.id)
|
280
|
+
Resque.enqueue_at(2.minutes.from_now, SendNotifications, :user_id => current_user.id)
|
281
|
+
|
282
|
+
# delay running the two jobs until 5 minutes from now
|
283
|
+
Resque.delay_or_enqueue_at(5.minutes.from_now, SendNotifications, :user_id => current_user.id)
|
284
|
+
```
|
285
|
+
|
286
|
+
The most useful case for increasing the delay of an already delayed job is to batch together work based on multiple events. For example, if you wanted to send a notification email to a user when an event triggers but didn't want to send 10 emails if many events happened within a short period, you could use this technique to delay the noficication email until no events have triggered for a period of time. This way you could send 1 email containing the 10 notifications once no events have triggered for 2 minutes. You could implement this like so:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
# Send a notification when an event is created.
|
290
|
+
# app/models/event.rb
|
291
|
+
after_commit on: :create do
|
292
|
+
Resque.delay_or_enqueue_in(2.minutes, SendNotifications, :user_id => user.id)
|
293
|
+
end
|
294
|
+
```
|
295
|
+
|
296
|
+
When the first event is created a job will be scheduled to send unsent notifications to the associated user. If another event is created within the 2 minute window, the timer will be reset to 2 minutes. This will continue as long as new events are created for the specific user before the 2 minute timer expires. Once the timer expires and the job is scheduled any new events that are created will schedule a new job and start the process over. By adjusting the window you can tweak the trade-off between sending notification emails quickly after an event happens and sending fewer emails.
|
297
|
+
|
298
|
+
Read more in the [original PR](https://github.com/resque/resque-scheduler/pull/645)
|
299
|
+
|
300
|
+
|
189
301
|
### Scheduled Jobs (Recurring Jobs)
|
190
302
|
|
191
303
|
Scheduled (or recurring) jobs are logically no different than a standard cron
|
@@ -231,6 +343,18 @@ clear_leaderboards_contributors:
|
|
231
343
|
description: "This job resets the weekly leaderboard for contributions"
|
232
344
|
```
|
233
345
|
|
346
|
+
If you would like to setup a job that is executed manually you can configure like this in your YAML file.
|
347
|
+
|
348
|
+
```yaml
|
349
|
+
ImportOrdersManual:
|
350
|
+
custom_job_class: 'AmazonMws::ImportOrdersJob'
|
351
|
+
never: "* * * * *"
|
352
|
+
queue: high
|
353
|
+
description: "This is a manual job for importing orders."
|
354
|
+
args:
|
355
|
+
days_in_arrears: 7
|
356
|
+
```
|
357
|
+
|
234
358
|
The queue value is optional, but if left unspecified resque-scheduler will
|
235
359
|
attempt to get the queue from the job class, which means it needs to be
|
236
360
|
defined. If you're getting "uninitialized constant" errors, you probably
|
@@ -254,7 +378,7 @@ resulting in resetting schedule time on every deploy, so it's probably a good id
|
|
254
378
|
frequent jobs (like every 10-30 minutes), otherwise - when you use something like `every 20h` and deploy once-twice per day -
|
255
379
|
it will schedule the job for 20 hours from deploy, resulting in a job to never be run.
|
256
380
|
|
257
|
-
NOTE
|
381
|
+
**NOTE**: Six parameter cron's are also supported (as they supported by
|
258
382
|
rufus-scheduler which powers the resque-scheduler process). This allows you
|
259
383
|
to schedule jobs per second (ie: `"30 * * * * *"` would fire a job every 30
|
260
384
|
seconds past the minute).
|
@@ -262,11 +386,43 @@ seconds past the minute).
|
|
262
386
|
A big shout out to [rufus-scheduler](http://github.com/jmettraux/rufus-scheduler)
|
263
387
|
for handling the heavy lifting of the actual scheduling engine.
|
264
388
|
|
389
|
+
##### Queue with parameters
|
390
|
+
|
391
|
+
It's possible to specify parameters, that must be given by the user when they manually queue the job. To enable this feature add `parameters` key to scheduled job definition.
|
392
|
+
|
393
|
+
```yaml
|
394
|
+
queue_documents_for_indexing:
|
395
|
+
cron: "0 0 * * *"
|
396
|
+
class: "QueueDocuments"
|
397
|
+
queue: high
|
398
|
+
args:
|
399
|
+
foo: "bar"
|
400
|
+
a: "b"
|
401
|
+
parameters:
|
402
|
+
foo:
|
403
|
+
description: "value of foo"
|
404
|
+
default: "baz"
|
405
|
+
|
406
|
+
description: "This job queues all content for indexing in solr"
|
407
|
+
```
|
408
|
+
|
409
|
+
One can use following options for each parameter:
|
410
|
+
* description - tooltip to be shown next to the parameter input
|
411
|
+
* default - prefilled value in the parameter input
|
412
|
+
|
413
|
+
**NOTE**: When sheduling the job, parameters are merged into job args. Assuming the example above and default parametr value, the job will be run with the following args:
|
414
|
+
|
415
|
+
```ruby
|
416
|
+
{"foo"=>"baz", "a"=>"b"}
|
417
|
+
```
|
418
|
+
|
419
|
+
**NOTE**: If user leaves the parameter value empty, it'll be sent as empty string.
|
420
|
+
|
265
421
|
#### Dynamic schedules
|
266
422
|
|
267
423
|
Dynamic schedules are programmatically set on a running `resque-scheduler`.
|
268
|
-
|
269
|
-
when setting schedules.
|
424
|
+
Most [rufus-scheduler](http://github.com/jmettraux/rufus-scheduler) options are supported
|
425
|
+
when setting schedules. Specifically the `overlap` option will not work.
|
270
426
|
|
271
427
|
Dynamic schedules are not enabled by default. To be able to dynamically set schedules, you
|
272
428
|
must pass the following to `resque-scheduler` initialization (see *Installation* above for a more complete example):
|
@@ -275,6 +431,10 @@ must pass the following to `resque-scheduler` initialization (see *Installation*
|
|
275
431
|
Resque::Scheduler.dynamic = true
|
276
432
|
```
|
277
433
|
|
434
|
+
**NOTE**: In order to delete dynamic schedules via `resque-web` in the
|
435
|
+
"Schedule" tab, you must include the `Rack::MethodOverride` middleware (in
|
436
|
+
`config.ru` or equivalent).
|
437
|
+
|
278
438
|
Dynamic schedules allow for greater flexibility than static schedules as they can be set,
|
279
439
|
unset or changed without having to restart `resque-scheduler`. You can specify, if the schedule
|
280
440
|
must survive a resque-scheduler restart or not. This is done by setting the `persist` configuration
|
@@ -319,18 +479,17 @@ Resque.set_schedule(name, config)
|
|
319
479
|
|
320
480
|
#### Time zones
|
321
481
|
|
322
|
-
|
323
|
-
rather than the `config.time_zone` specified in Rails.
|
324
|
-
|
482
|
+
If you use the cron syntax, by default it is interpreted in the server time zone.
|
325
483
|
You can explicitly specify the time zone that rufus-scheduler will use:
|
326
|
-
|
327
484
|
```yaml
|
328
485
|
cron: "30 6 * * 1 Europe/Stockholm"
|
329
486
|
```
|
330
487
|
|
331
|
-
|
332
|
-
|
333
|
-
|
488
|
+
##### Rails
|
489
|
+
In Rails, `config.time_zone` will be used to determine the time zone for `resque-scheduler`.
|
490
|
+
|
491
|
+
Note that `config.time_zone` allows for a shorthand (e.g. "Stockholm")
|
492
|
+
that rufus-scheduler does not accept, so make sure it's the right format, e.g. with:
|
334
493
|
|
335
494
|
```ruby
|
336
495
|
ActiveSupport::TimeZone.find_tzinfo(Rails.configuration.time_zone).name
|
@@ -353,6 +512,13 @@ Similar to the `before_enqueue`- and `after_enqueue`-hooks provided in Resque
|
|
353
512
|
removed from the delayed queue, but not yet put on a normal queue. It is
|
354
513
|
called before `before_enqueue`-hooks, and on the same job instance as the
|
355
514
|
`before_enqueue`-hooks will be invoked on. Return values are ignored.
|
515
|
+
* `on_enqueue_failure`: Called with the job args and the exception that was raised
|
516
|
+
while enqueueing a job to resque or external application fails. Return
|
517
|
+
values are ignored. For example:
|
518
|
+
|
519
|
+
```ruby
|
520
|
+
Resque::Scheduler.failure_handler = ExceptionHandlerClass
|
521
|
+
```
|
356
522
|
|
357
523
|
#### Support for resque-status (and other custom jobs)
|
358
524
|
|
@@ -405,13 +571,13 @@ end
|
|
405
571
|
*>= 2.0.1 only. Prior to 2.0.1, it is not recommended to run multiple resque-scheduler processes and will result in duplicate jobs.*
|
406
572
|
|
407
573
|
You may want to have resque-scheduler running on multiple machines for
|
408
|
-
|
574
|
+
redundancy. Electing a master and failover is built in and default. Simply
|
409
575
|
run resque-scheduler on as many machine as you want pointing to the same
|
410
576
|
redis instance and schedule. The scheduler processes will use redis to
|
411
577
|
elect a master process and detect failover when the master dies. Precautions are
|
412
578
|
taken to prevent jobs from potentially being queued twice during failover even
|
413
579
|
when the clocks of the scheduler machines are slightly out of sync (or load affects
|
414
|
-
scheduled job firing time). If you want the gory details, look at Resque::
|
580
|
+
scheduled job firing time). If you want the gory details, look at Resque::Scheduler::Locking.
|
415
581
|
|
416
582
|
If the scheduler process(es) goes down for whatever reason, the delayed items
|
417
583
|
that should have fired during the outage will fire once the scheduler process
|
@@ -426,11 +592,13 @@ run, leading to undesired behaviour. To allow different scheduler configs run at
|
|
426
592
|
on one redis, you can either namespace your redis connections, or supply an environment variable
|
427
593
|
to split the shared lock key resque-scheduler uses thus:
|
428
594
|
|
429
|
-
|
595
|
+
``` bash
|
596
|
+
RESQUE_SCHEDULER_MASTER_LOCK_PREFIX=MyApp: rake resque:scheduler
|
597
|
+
```
|
430
598
|
|
431
599
|
### resque-web Additions
|
432
600
|
|
433
|
-
Resque-scheduler also adds
|
601
|
+
Resque-scheduler also adds two tabs to the resque-web UI. One is for viewing
|
434
602
|
(and manually queueing) the schedule and one is for viewing pending jobs in
|
435
603
|
the delayed queue.
|
436
604
|
|
@@ -458,18 +626,13 @@ Now, you want to add the following:
|
|
458
626
|
|
459
627
|
```ruby
|
460
628
|
# This will make the tabs show up.
|
461
|
-
require '
|
462
|
-
require '
|
629
|
+
require 'resque-scheduler'
|
630
|
+
require 'resque/scheduler/server'
|
463
631
|
```
|
464
632
|
|
465
633
|
That should make the scheduler tabs show up in `resque-web`.
|
466
634
|
|
467
|
-
|
468
|
-
#### Changes as of 2.0.0
|
469
|
-
|
470
|
-
As of resque-scheduler 2.0.0, it's no longer necessary to have the resque-web
|
471
|
-
process aware of the schedule because it reads it from redis. But prior to
|
472
|
-
2.0, you'll want to make sure you load the schedule in this file as well.
|
635
|
+
You'll want to make sure you load the schedule in this file as well.
|
473
636
|
Something like this:
|
474
637
|
|
475
638
|
```ruby
|
@@ -483,7 +646,7 @@ Now make sure you're passing that file to resque-web like so:
|
|
483
646
|
|
484
647
|
### Running in the background
|
485
648
|
|
486
|
-
|
649
|
+
There are scenarios where it's helpful for
|
487
650
|
the resque worker to run itself in the background (usually in combination with
|
488
651
|
PIDFILE). Use the BACKGROUND option so that rake will return as soon as the
|
489
652
|
worker is started.
|
@@ -497,10 +660,10 @@ worker is started.
|
|
497
660
|
There are several options to toggle the way scheduler logs its actions. They
|
498
661
|
are toggled by environment variables:
|
499
662
|
|
500
|
-
- `
|
501
|
-
- `VERBOSE` opposite of '
|
663
|
+
- `QUIET` will stop logging anything. Completely silent.
|
664
|
+
- `VERBOSE` opposite of 'QUIET'; will log even debug information
|
502
665
|
- `LOGFILE` specifies the file to write logs to. (default standard output)
|
503
|
-
- `LOGFORMAT` specifies either "text" or "
|
666
|
+
- `LOGFORMAT` specifies either "text", "json" or "logfmt" output format
|
504
667
|
(default "text")
|
505
668
|
|
506
669
|
All of these variables are optional and will be given the following default
|
@@ -508,7 +671,7 @@ values:
|
|
508
671
|
|
509
672
|
```ruby
|
510
673
|
Resque::Scheduler.configure do |c|
|
511
|
-
c.
|
674
|
+
c.quiet = false
|
512
675
|
c.verbose = false
|
513
676
|
c.logfile = nil # meaning all messages go to $stdout
|
514
677
|
c.logformat = 'text'
|
@@ -534,6 +697,64 @@ of the code looking very similar to resque, particularly in resque-web
|
|
534
697
|
and the views. I wanted it to be similar enough that someone familiar
|
535
698
|
with resque could easily work on resque-scheduler.
|
536
699
|
|
700
|
+
### Development
|
701
|
+
|
702
|
+
Working on resque-scheduler requires the following:
|
703
|
+
|
704
|
+
* A relatively modern Ruby interpreter
|
705
|
+
* bundler
|
706
|
+
|
707
|
+
The development setup looks like this, which is roughly the same thing
|
708
|
+
that happens on Travis CI and Appveyor:
|
709
|
+
|
710
|
+
``` bash
|
711
|
+
# Install everything
|
712
|
+
bundle install
|
713
|
+
|
714
|
+
# Make sure tests are green before you change stuff
|
715
|
+
bundle exec rubocop && bundle exec rake
|
716
|
+
# Change stuff
|
717
|
+
# Repeat
|
718
|
+
```
|
719
|
+
|
720
|
+
If you have [vagrant](http://www.vagrantup.com) installed, there is a
|
721
|
+
development box available that requires no plugins or external
|
722
|
+
provisioners:
|
723
|
+
|
724
|
+
``` bash
|
725
|
+
vagrant up
|
726
|
+
```
|
727
|
+
|
728
|
+
### Deployment Notes
|
729
|
+
|
730
|
+
It is recommended that a production deployment of `resque-scheduler` be hosted
|
731
|
+
on a dedicated Redis database. While making and managing scheduled tasks,
|
732
|
+
`resque-scheduler` currently scans the entire Redis keyspace, which may cause
|
733
|
+
latency and stability issues if `resque-scheduler` is hosted on a Redis instance
|
734
|
+
storing a large number of keys (such as those written by a different system
|
735
|
+
hosted on the same Redis instance).
|
736
|
+
|
737
|
+
#### Compatibility Notes
|
738
|
+
|
739
|
+
Different versions of the `redis` and `rufus-scheduler` gems are needed
|
740
|
+
depending on your version of `resque-scheduler`. This is typically not a
|
741
|
+
problem with `resque-scheduler` itself, but when mixing dependencies with an
|
742
|
+
existing application.
|
743
|
+
|
744
|
+
This table explains the version requirements for redis gem
|
745
|
+
|
746
|
+
| resque-scheduler | redis gem |
|
747
|
+
|:-----------------|-----------:|
|
748
|
+
| `~> 2.0` | `>= 3.0.0` |
|
749
|
+
| `>= 0.0.1` | `~> 1.3` |
|
750
|
+
|
751
|
+
This table explains the version requirements for rufus-scheduler
|
752
|
+
|
753
|
+
| resque-scheduler | rufus-scheduler |
|
754
|
+
|:-----------------|----------------:|
|
755
|
+
| `~> 4.0` | `~> 3.0` |
|
756
|
+
| `< 4.0` | `~> 2.0` |
|
757
|
+
|
537
758
|
|
538
759
|
### Contributing
|
539
760
|
|
data/Rakefile
CHANGED
@@ -1,29 +1,18 @@
|
|
1
|
+
# vim:fileencoding=utf-8
|
1
2
|
require 'bundler/gem_tasks'
|
2
3
|
require 'rake/testtask'
|
4
|
+
require 'yard'
|
3
5
|
|
4
|
-
task default:
|
6
|
+
task default: :test
|
5
7
|
|
6
8
|
Rake::TestTask.new do |t|
|
7
9
|
t.libs << 'test'
|
8
10
|
t.pattern = ENV['PATTERN'] || 'test/*_test.rb'
|
9
|
-
t.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
desc 'Run rubocop'
|
14
|
-
task :rubocop do
|
15
|
-
unless RUBY_VERSION < '1.9'
|
16
|
-
sh('rubocop --format simple') { |ok, _| ok || abort }
|
11
|
+
t.options = ''.tap do |o|
|
12
|
+
o << "--seed #{ENV['SEED']} " if ENV['SEED']
|
13
|
+
o << '--verbose ' if ENV['VERBOSE']
|
17
14
|
end
|
15
|
+
t.warning = false
|
18
16
|
end
|
19
17
|
|
20
|
-
|
21
|
-
require 'rdoc/task'
|
22
|
-
|
23
|
-
Rake::RDocTask.new do |rd|
|
24
|
-
rd.main = 'README.md'
|
25
|
-
rd.rdoc_files.include('README.md', 'lib/**/*.rb')
|
26
|
-
rd.rdoc_dir = 'doc'
|
27
|
-
end
|
28
|
-
rescue LoadError
|
29
|
-
end
|
18
|
+
YARD::Rake::YardocTask.new
|