resque 1.23.0 → 2.6.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/HISTORY.md +271 -0
- data/README.markdown +454 -484
- data/Rakefile +4 -17
- data/bin/resque-web +10 -22
- data/lib/resque/data_store.rb +335 -0
- data/lib/resque/errors.rb +15 -1
- data/lib/resque/failure/airbrake.rb +32 -4
- data/lib/resque/failure/base.rb +16 -7
- data/lib/resque/failure/multiple.rb +26 -8
- data/lib/resque/failure/redis.rb +92 -15
- data/lib/resque/failure/redis_multi_queue.rb +104 -0
- data/lib/resque/failure.rb +62 -32
- data/lib/resque/helpers.rb +11 -57
- data/lib/resque/job.rb +79 -12
- data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
- data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
- data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
- data/lib/resque/logging.rb +18 -0
- data/lib/resque/plugin.rb +22 -10
- data/lib/resque/railtie.rb +10 -0
- data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
- data/lib/resque/server/public/jquery.relatize_date.js +4 -4
- data/lib/resque/server/public/main.js +3 -0
- data/lib/resque/server/public/ranger.js +16 -8
- data/lib/resque/server/public/style.css +13 -8
- data/lib/resque/server/views/error.erb +1 -1
- data/lib/resque/server/views/failed.erb +27 -59
- data/lib/resque/server/views/failed_job.erb +50 -0
- data/lib/resque/server/views/failed_queues_overview.erb +24 -0
- data/lib/resque/server/views/job_class.erb +8 -0
- data/lib/resque/server/views/key_sets.erb +2 -4
- data/lib/resque/server/views/key_string.erb +1 -1
- data/lib/resque/server/views/layout.erb +7 -6
- data/lib/resque/server/views/next_more.erb +22 -10
- data/lib/resque/server/views/processing.erb +2 -0
- data/lib/resque/server/views/queues.erb +22 -13
- data/lib/resque/server/views/stats.erb +5 -5
- data/lib/resque/server/views/workers.erb +4 -4
- data/lib/resque/server/views/working.erb +10 -11
- data/lib/resque/server.rb +51 -108
- data/lib/resque/server_helper.rb +185 -0
- data/lib/resque/stat.rb +19 -7
- data/lib/resque/tasks.rb +26 -25
- data/lib/resque/thread_signal.rb +24 -0
- data/lib/resque/vendor/utf8_util.rb +2 -8
- data/lib/resque/version.rb +1 -1
- data/lib/resque/web_runner.rb +374 -0
- data/lib/resque/worker.rb +487 -163
- data/lib/resque.rb +332 -52
- data/lib/tasks/redis.rake +11 -11
- metadata +169 -149
- data/lib/resque/failure/hoptoad.rb +0 -33
- data/lib/resque/failure/thoughtbot.rb +0 -33
- data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
- data/lib/resque/server/test_helper.rb +0 -19
- data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
- data/test/airbrake_test.rb +0 -27
- data/test/hoptoad_test.rb +0 -26
- data/test/job_hooks_test.rb +0 -464
- data/test/job_plugins_test.rb +0 -230
- data/test/plugin_test.rb +0 -116
- data/test/redis-test-cluster.conf +0 -115
- data/test/redis-test.conf +0 -115
- data/test/resque-web_test.rb +0 -59
- data/test/resque_failure_redis_test.rb +0 -19
- data/test/resque_test.rb +0 -278
- data/test/test_helper.rb +0 -178
- data/test/worker_test.rb +0 -657
data/README.markdown
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
Resque
|
|
2
2
|
======
|
|
3
3
|
|
|
4
|
+
[](https://rubygems.org/gems/resque)
|
|
5
|
+
[](https://github.com/resque/resque/actions/workflows/ci.yml)
|
|
6
|
+
|
|
7
|
+
Introduction
|
|
8
|
+
------------
|
|
9
|
+
|
|
4
10
|
Resque (pronounced like "rescue") is a Redis-backed library for creating
|
|
5
11
|
background jobs, placing those jobs on multiple queues, and processing
|
|
6
12
|
them later.
|
|
7
13
|
|
|
14
|
+
For the backstory, philosophy, and history of Resque's beginnings, please see [the blog post](http://github.com/blog/542-introducing-resque) (2009).
|
|
15
|
+
|
|
8
16
|
Background jobs can be any Ruby class or module that responds to
|
|
9
17
|
`perform`. Your existing classes can easily be converted to background
|
|
10
18
|
jobs or you can create new classes specifically to do work. Or, you
|
|
@@ -17,10 +25,11 @@ three parts:
|
|
|
17
25
|
2. A Rake task for starting a worker which processes jobs
|
|
18
26
|
3. A Sinatra app for monitoring queues, jobs, and workers.
|
|
19
27
|
|
|
20
|
-
Resque workers can be
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
Resque workers can be given multiple queues (a "queue list"),
|
|
29
|
+
distributed between multiple machines,
|
|
30
|
+
run anywhere with network access to the Redis server,
|
|
31
|
+
support priorities, are resilient to memory bloat / "leaks,"
|
|
32
|
+
tell you what they're doing, and expect failure.
|
|
24
33
|
|
|
25
34
|
Resque queues are persistent; support constant time, atomic push and
|
|
26
35
|
pop (thanks to Redis); provide visibility into their contents; and
|
|
@@ -30,19 +39,18 @@ The Resque frontend tells you what workers are doing, what workers are
|
|
|
30
39
|
not doing, what queues you're using, what's in those queues, provides
|
|
31
40
|
general usage stats, and helps you track failures.
|
|
32
41
|
|
|
42
|
+
Resque now supports Ruby 2.3.0 and above.
|
|
43
|
+
We will also only be supporting Redis 3.0 and above going forward.
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
-------------
|
|
36
|
-
|
|
37
|
-
For the backstory, philosophy, and history of Resque's beginnings,
|
|
38
|
-
please see [the blog post][0].
|
|
45
|
+
### Note on the future of Resque
|
|
39
46
|
|
|
47
|
+
Would you like to be involved in Resque? Do you have thoughts about what
|
|
48
|
+
Resque should be and do going forward? There's currently an [open discussion here](https://github.com/resque/resque/issues/1759)
|
|
49
|
+
on just that topic, so please feel free to join in. We'd love to hear your thoughts
|
|
50
|
+
and/or have people volunteer to be a part of the project!
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Resque allows you to create jobs and place them on a queue, then,
|
|
45
|
-
later, pull those jobs off the queue and process them.
|
|
52
|
+
Example
|
|
53
|
+
-------
|
|
46
54
|
|
|
47
55
|
Resque jobs are Ruby classes (or modules) which respond to the
|
|
48
56
|
`perform` method. Here's an example:
|
|
@@ -102,105 +110,42 @@ This starts one Resque worker and tells it to work off the
|
|
|
102
110
|
find any more, at which point it will sleep for a small period and
|
|
103
111
|
repeatedly poll the queue for more jobs.
|
|
104
112
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
access to the Redis server.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Jobs
|
|
111
|
-
----
|
|
112
|
-
|
|
113
|
-
What should you run in the background? Anything that takes any time at
|
|
114
|
-
all. Slow INSERT statements, disk manipulating, data processing, etc.
|
|
115
|
-
|
|
116
|
-
At GitHub we use Resque to process the following types of jobs:
|
|
113
|
+
Installation
|
|
114
|
+
------------
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
* Counting disk usage
|
|
120
|
-
* Building tarballs
|
|
121
|
-
* Building Rubygems
|
|
122
|
-
* Firing off web hooks
|
|
123
|
-
* Creating events in the db and pre-caching them
|
|
124
|
-
* Building graphs
|
|
125
|
-
* Deleting users
|
|
126
|
-
* Updating our search index
|
|
116
|
+
Add the gem to your Gemfile:
|
|
127
117
|
|
|
128
|
-
|
|
118
|
+
gem 'resque'
|
|
129
119
|
|
|
130
|
-
|
|
131
|
-
mention "foreground" and "background" because they make conceptual
|
|
132
|
-
sense. You could easily be spidering sites and sticking data which
|
|
133
|
-
needs to be crunched later into a queue.
|
|
120
|
+
Next, install it with Bundler:
|
|
134
121
|
|
|
122
|
+
$ bundle
|
|
135
123
|
|
|
136
|
-
|
|
124
|
+
#### Rack
|
|
137
125
|
|
|
138
|
-
|
|
139
|
-
example from above. We'll run the following code to create a job:
|
|
126
|
+
In your Rakefile, or some other file in `lib/tasks` (ex: `lib/tasks/resque.rake`), load the resque rake tasks:
|
|
140
127
|
|
|
141
128
|
``` ruby
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
The following JSON will be stored in the `file_serve` queue:
|
|
147
|
-
|
|
148
|
-
``` javascript
|
|
149
|
-
{
|
|
150
|
-
'class': 'Archive',
|
|
151
|
-
'args': [ 44, 'masterbrew' ]
|
|
152
|
-
}
|
|
129
|
+
require 'resque'
|
|
130
|
+
require 'resque/tasks'
|
|
131
|
+
require 'your/app' # Include this line if you want your workers to have access to your application
|
|
153
132
|
```
|
|
154
133
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
So instead of doing this:
|
|
158
|
-
|
|
159
|
-
``` ruby
|
|
160
|
-
Resque.enqueue(Archive, self, branch)
|
|
161
|
-
```
|
|
134
|
+
#### Rails
|
|
162
135
|
|
|
163
|
-
|
|
136
|
+
To make resque specific changes, you can override the `resque:setup` job in `lib/tasks` (ex: `lib/tasks/resque.rake`). GitHub's setup task looks like this:
|
|
164
137
|
|
|
165
138
|
``` ruby
|
|
166
|
-
|
|
139
|
+
task "resque:setup" => :environment do
|
|
140
|
+
Grit::Git.git_timeout = 10.minutes
|
|
141
|
+
end
|
|
167
142
|
```
|
|
168
143
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
While this is less convenient than just sticking a marshaled object
|
|
173
|
-
in the database, it gives you a slight advantage: your jobs will be
|
|
174
|
-
run against the most recent version of an object because they need to
|
|
175
|
-
pull from the DB or cache.
|
|
176
|
-
|
|
177
|
-
If your jobs were run against marshaled objects, they could
|
|
178
|
-
potentially be operating on a stale record with out-of-date information.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
### send_later / async
|
|
182
|
-
|
|
183
|
-
Want something like DelayedJob's `send_later` or the ability to use
|
|
184
|
-
instance methods instead of just methods for jobs? See the `examples/`
|
|
185
|
-
directory for goodies.
|
|
186
|
-
|
|
187
|
-
We plan to provide first class `async` support in a future release.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
### Failure
|
|
191
|
-
|
|
192
|
-
If a job raises an exception, it is logged and handed off to the
|
|
193
|
-
`Resque::Failure` module. Failures are logged either locally in Redis
|
|
194
|
-
or using some different backend.
|
|
195
|
-
|
|
196
|
-
For example, Resque ships with Hoptoad support.
|
|
197
|
-
|
|
198
|
-
Keep this in mind when writing your jobs: you may want to throw
|
|
199
|
-
exceptions you would not normally throw in order to assist debugging.
|
|
200
|
-
|
|
144
|
+
We don't want the `git_timeout` as high as 10 minutes in our web app,
|
|
145
|
+
but in the Resque workers it's fine.
|
|
201
146
|
|
|
202
|
-
Workers
|
|
203
|
-
|
|
147
|
+
Running Workers
|
|
148
|
+
---------------
|
|
204
149
|
|
|
205
150
|
Resque workers are rake tasks that run forever. They basically do this:
|
|
206
151
|
|
|
@@ -210,79 +155,24 @@ loop do
|
|
|
210
155
|
if job = reserve
|
|
211
156
|
job.process
|
|
212
157
|
else
|
|
213
|
-
sleep 5 # Polling frequency = 5
|
|
158
|
+
sleep 5 # Polling frequency = 5
|
|
214
159
|
end
|
|
215
160
|
end
|
|
216
161
|
shutdown
|
|
217
162
|
```
|
|
218
163
|
|
|
219
|
-
Starting a worker is simple
|
|
220
|
-
|
|
221
|
-
$ QUEUE=file_serve rake resque:work
|
|
222
|
-
|
|
223
|
-
By default Resque won't know about your application's
|
|
224
|
-
environment. That is, it won't be able to find and run your jobs - it
|
|
225
|
-
needs to load your application into memory.
|
|
226
|
-
|
|
227
|
-
If we've installed Resque as a Rails plugin, we might run this command
|
|
228
|
-
from our RAILS_ROOT:
|
|
229
|
-
|
|
230
|
-
$ QUEUE=file_serve rake environment resque:work
|
|
231
|
-
|
|
232
|
-
This will load the environment before starting a worker. Alternately
|
|
233
|
-
we can define a `resque:setup` task with a dependency on the
|
|
234
|
-
`environment` rake task:
|
|
235
|
-
|
|
236
|
-
``` ruby
|
|
237
|
-
task "resque:setup" => :environment
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
GitHub's setup task looks like this:
|
|
241
|
-
|
|
242
|
-
``` ruby
|
|
243
|
-
task "resque:setup" => :environment do
|
|
244
|
-
Grit::Git.git_timeout = 10.minutes
|
|
245
|
-
end
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
We don't want the `git_timeout` as high as 10 minutes in our web app,
|
|
249
|
-
but in the Resque workers it's fine.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
### Logging
|
|
164
|
+
Starting a worker is simple:
|
|
253
165
|
|
|
254
|
-
|
|
255
|
-
`VERBOSE` env variable set, they will print basic debugging
|
|
256
|
-
information. You can also set the `VVERBOSE` (very verbose) env
|
|
257
|
-
variable.
|
|
258
|
-
|
|
259
|
-
$ VVERBOSE=1 QUEUE=file_serve rake environment resque:work
|
|
260
|
-
|
|
261
|
-
### Process IDs (PIDs)
|
|
262
|
-
|
|
263
|
-
There are scenarios where it's helpful to record the PID of a resque
|
|
264
|
-
worker process. Use the PIDFILE option for easy access to the PID:
|
|
265
|
-
|
|
266
|
-
$ PIDFILE=./resque.pid QUEUE=file_serve rake environment resque:work
|
|
267
|
-
|
|
268
|
-
### Running in the background
|
|
269
|
-
|
|
270
|
-
(Only supported with ruby >= 1.9). There are scenarios where it's helpful for
|
|
271
|
-
the resque worker to run itself in the background (usually in combination with
|
|
272
|
-
PIDFILE). Use the BACKGROUND option so that rake will return as soon as the
|
|
273
|
-
worker is started.
|
|
274
|
-
|
|
275
|
-
$ PIDFILE=./resque.pid BACKGROUND=yes QUEUE=file_serve \
|
|
276
|
-
rake environment resque:work
|
|
166
|
+
$ QUEUE=* rake resque:work
|
|
277
167
|
|
|
278
|
-
|
|
168
|
+
Or, you can start multiple workers:
|
|
279
169
|
|
|
280
|
-
|
|
281
|
-
The default is 5 seconds, but for a semi-active app you may want to use a smaller value.
|
|
170
|
+
$ COUNT=2 QUEUE=* rake resque:workers
|
|
282
171
|
|
|
283
|
-
|
|
172
|
+
This will spawn two Resque workers, each in its own process. Hitting
|
|
173
|
+
ctrl-c should be sufficient to stop them all.
|
|
284
174
|
|
|
285
|
-
|
|
175
|
+
#### Priorities and Queue Lists
|
|
286
176
|
|
|
287
177
|
Resque doesn't support numeric priorities but instead uses the order
|
|
288
178
|
of queues you give it. We call this list of queues the "queue list."
|
|
@@ -316,8 +206,7 @@ And workers on our specialized archive machine with this command:
|
|
|
316
206
|
|
|
317
207
|
$ QUEUE=archive rake resque:work
|
|
318
208
|
|
|
319
|
-
|
|
320
|
-
### Running All Queues
|
|
209
|
+
#### Running All Queues
|
|
321
210
|
|
|
322
211
|
If you want your workers to work off of every queue, including new
|
|
323
212
|
queues created on the fly, you can use a splat:
|
|
@@ -326,113 +215,51 @@ queues created on the fly, you can use a splat:
|
|
|
326
215
|
|
|
327
216
|
Queues will be processed in alphabetical order.
|
|
328
217
|
|
|
218
|
+
Or, prioritize some queues above `*`:
|
|
329
219
|
|
|
330
|
-
|
|
220
|
+
# QUEUE=critical,* rake resque:work
|
|
331
221
|
|
|
332
|
-
|
|
333
|
-
configuration file is included under `examples/god`. We recommend this
|
|
334
|
-
method.
|
|
222
|
+
#### Running All Queues Except for Some
|
|
335
223
|
|
|
336
|
-
If you
|
|
337
|
-
|
|
224
|
+
If you want your workers to work off of all queues except for some,
|
|
225
|
+
you can use negation:
|
|
338
226
|
|
|
339
|
-
$
|
|
227
|
+
$ QUEUE=*,!low rake resque:work
|
|
340
228
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
### Forking
|
|
346
|
-
|
|
347
|
-
On certain platforms, when a Resque worker reserves a job it
|
|
348
|
-
immediately forks a child process. The child processes the job then
|
|
349
|
-
exits. When the child has exited successfully, the worker reserves
|
|
350
|
-
another job and repeats the process.
|
|
351
|
-
|
|
352
|
-
Why?
|
|
353
|
-
|
|
354
|
-
Because Resque assumes chaos.
|
|
355
|
-
|
|
356
|
-
Resque assumes your background workers will lock up, run too long, or
|
|
357
|
-
have unwanted memory growth.
|
|
358
|
-
|
|
359
|
-
If Resque workers processed jobs themselves, it'd be hard to whip them
|
|
360
|
-
into shape. Let's say one is using too much memory: you send it a
|
|
361
|
-
signal that says "shutdown after you finish processing the current
|
|
362
|
-
job," and it does so. It then starts up again - loading your entire
|
|
363
|
-
application environment. This adds useless CPU cycles and causes a
|
|
364
|
-
delay in queue processing.
|
|
365
|
-
|
|
366
|
-
Plus, what if it's using too much memory and has stopped responding to
|
|
367
|
-
signals?
|
|
368
|
-
|
|
369
|
-
Thanks to Resque's parent / child architecture, jobs that use too much memory
|
|
370
|
-
release that memory upon completion. No unwanted growth.
|
|
371
|
-
|
|
372
|
-
And what if a job is running too long? You'd need to `kill -9` it then
|
|
373
|
-
start the worker again. With Resque's parent / child architecture you
|
|
374
|
-
can tell the parent to forcefully kill the child then immediately
|
|
375
|
-
start processing more jobs. No startup delay or wasted cycles.
|
|
376
|
-
|
|
377
|
-
The parent / child architecture helps us keep tabs on what workers are
|
|
378
|
-
doing, too. By eliminating the need to `kill -9` workers we can have
|
|
379
|
-
parents remove themselves from the global listing of workers. If we
|
|
380
|
-
just ruthlessly killed workers, we'd need a separate watchdog process
|
|
381
|
-
to add and remove them to the global listing - which becomes
|
|
382
|
-
complicated.
|
|
383
|
-
|
|
384
|
-
Workers instead handle their own state.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
### Parents and Children
|
|
388
|
-
|
|
389
|
-
Here's a parent / child pair doing some work:
|
|
390
|
-
|
|
391
|
-
$ ps -e -o pid,command | grep [r]esque
|
|
392
|
-
92099 resque: Forked 92102 at 1253142769
|
|
393
|
-
92102 resque: Processing file_serve since 1253142769
|
|
394
|
-
|
|
395
|
-
You can clearly see that process 92099 forked 92102, which has been
|
|
396
|
-
working since 1253142769.
|
|
397
|
-
|
|
398
|
-
(By advertising the time they began processing you can easily use monit
|
|
399
|
-
or god to kill stale workers.)
|
|
229
|
+
Negated globs also work. The following will instruct workers to work
|
|
230
|
+
off of all queues except those beginning with `file_`:
|
|
400
231
|
|
|
401
|
-
|
|
402
|
-
waiting for work on:
|
|
403
|
-
|
|
404
|
-
$ ps -e -o pid,command | grep [r]esque
|
|
405
|
-
92099 resque: Waiting for file_serve,warm_cache
|
|
232
|
+
$ QUEUE=*,!file_* rake resque:work
|
|
406
233
|
|
|
234
|
+
Note that the order in which negated queues are specified does not
|
|
235
|
+
matter, so `QUEUE=*,!file_*` and `QUEUE=!file_*,*` will have the same
|
|
236
|
+
effect.
|
|
407
237
|
|
|
408
|
-
|
|
238
|
+
#### Process IDs (PIDs)
|
|
409
239
|
|
|
410
|
-
|
|
240
|
+
There are scenarios where it's helpful to record the PID of a resque
|
|
241
|
+
worker process. Use the PIDFILE option for easy access to the PID:
|
|
411
242
|
|
|
412
|
-
|
|
413
|
-
* `TERM` / `INT` - Immediately kill child then exit
|
|
414
|
-
* `USR1` - Immediately kill child but don't exit
|
|
415
|
-
* `USR2` - Don't start to process any new jobs
|
|
416
|
-
* `CONT` - Start to process new jobs again after a USR2
|
|
243
|
+
$ PIDFILE=./resque.pid QUEUE=file_serve rake resque:work
|
|
417
244
|
|
|
418
|
-
|
|
245
|
+
#### Running in the background
|
|
419
246
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
247
|
+
There are scenarios where it's helpful for
|
|
248
|
+
the resque worker to run itself in the background (usually in combination with
|
|
249
|
+
PIDFILE). Use the BACKGROUND option so that rake will return as soon as the
|
|
250
|
+
worker is started.
|
|
423
251
|
|
|
424
|
-
|
|
252
|
+
$ PIDFILE=./resque.pid BACKGROUND=yes QUEUE=file_serve rake resque:work
|
|
425
253
|
|
|
426
|
-
|
|
427
|
-
(for example, to temporarily alleviate load), use `USR2` to stop processing,
|
|
428
|
-
then `CONT` to start it again.
|
|
254
|
+
#### Polling frequency
|
|
429
255
|
|
|
430
|
-
|
|
256
|
+
You can pass an INTERVAL option which is a float representing the polling frequency.
|
|
257
|
+
The default is 5 seconds, but for a semi-active app you may want to use a smaller value.
|
|
431
258
|
|
|
432
|
-
|
|
433
|
-
connection. If that happens we recommend using [this
|
|
434
|
-
Gist](http://gist.github.com/238999).
|
|
259
|
+
$ INTERVAL=0.1 QUEUE=file_serve rake resque:work
|
|
435
260
|
|
|
261
|
+
When INTERVAL is set to 0 it will run until the queue is empty and then
|
|
262
|
+
shutdown the worker, instead of waiting for new jobs.
|
|
436
263
|
|
|
437
264
|
The Front End
|
|
438
265
|
-------------
|
|
@@ -440,9 +267,9 @@ The Front End
|
|
|
440
267
|
Resque comes with a Sinatra-based front end for seeing what's up with
|
|
441
268
|
your queue.
|
|
442
269
|
|
|
443
|
-

|
|
444
271
|
|
|
445
|
-
|
|
272
|
+
#### Standalone
|
|
446
273
|
|
|
447
274
|
If you've installed Resque as a gem running the front end standalone is easy:
|
|
448
275
|
|
|
@@ -465,15 +292,15 @@ or set the Redis connection string if you need to do something like select a dif
|
|
|
465
292
|
|
|
466
293
|
$ resque-web -p 8282 -r localhost:6379:2
|
|
467
294
|
|
|
468
|
-
|
|
295
|
+
#### Passenger
|
|
469
296
|
|
|
470
297
|
Using Passenger? Resque ships with a `config.ru` you can use. See
|
|
471
298
|
Phusion's guide:
|
|
472
299
|
|
|
473
|
-
Apache: <
|
|
474
|
-
Nginx: <
|
|
300
|
+
Apache: <https://www.phusionpassenger.com/library/deploy/apache/deploy/ruby/>
|
|
301
|
+
Nginx: <https://www.phusionpassenger.com/library/deploy/nginx/deploy/ruby/>
|
|
475
302
|
|
|
476
|
-
|
|
303
|
+
#### Rack::URLMap
|
|
477
304
|
|
|
478
305
|
If you want to load Resque on a subpath, possibly alongside other
|
|
479
306
|
apps, it's easy to do with Rack's `URLMap`:
|
|
@@ -489,229 +316,151 @@ run Rack::URLMap.new \
|
|
|
489
316
|
Check `examples/demo/config.ru` for a functional example (including
|
|
490
317
|
HTTP basic auth).
|
|
491
318
|
|
|
492
|
-
|
|
319
|
+
#### Rails
|
|
493
320
|
|
|
494
|
-
You can also mount Resque on a subpath in your existing Rails
|
|
321
|
+
You can also mount Resque on a subpath in your existing Rails app by adding `require 'resque/server'` to the top of your routes file or in an initializer then adding this to `routes.rb`:
|
|
495
322
|
|
|
496
323
|
``` ruby
|
|
497
324
|
mount Resque::Server.new, :at => "/resque"
|
|
498
325
|
```
|
|
499
326
|
|
|
327
|
+
Jobs
|
|
328
|
+
----
|
|
500
329
|
|
|
501
|
-
|
|
502
|
-
|
|
330
|
+
What should you run in the background? Anything that takes any time at
|
|
331
|
+
all. Slow INSERT statements, disk manipulating, data processing, etc.
|
|
503
332
|
|
|
504
|
-
|
|
505
|
-
over the other?
|
|
333
|
+
At GitHub we use Resque to process the following types of jobs:
|
|
506
334
|
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* DelayedJob can be queried from within your Rails app if you want to
|
|
517
|
-
add an interface
|
|
335
|
+
* Warming caches
|
|
336
|
+
* Counting disk usage
|
|
337
|
+
* Building tarballs
|
|
338
|
+
* Building Rubygems
|
|
339
|
+
* Firing off web hooks
|
|
340
|
+
* Creating events in the db and pre-caching them
|
|
341
|
+
* Building graphs
|
|
342
|
+
* Deleting users
|
|
343
|
+
* Updating our search index
|
|
518
344
|
|
|
519
|
-
|
|
520
|
-
ActiveRecord. DelayedJob is super easy to setup and works great.
|
|
521
|
-
GitHub used it for many months to process almost 200 million jobs.
|
|
345
|
+
As of writing we have about 35 different types of background jobs.
|
|
522
346
|
|
|
523
|
-
|
|
347
|
+
Keep in mind that you don't need a web app to use Resque - we just
|
|
348
|
+
mention "foreground" and "background" because they make conceptual
|
|
349
|
+
sense. You could easily be spidering sites and sticking data which
|
|
350
|
+
needs to be crunched later into a queue.
|
|
524
351
|
|
|
525
|
-
|
|
526
|
-
* You don't care / dislike numeric priorities
|
|
527
|
-
* You don't need to persist every Ruby object ever
|
|
528
|
-
* You have potentially huge queues
|
|
529
|
-
* You want to see what's going on
|
|
530
|
-
* You expect a lot of failure / chaos
|
|
531
|
-
* You can setup Redis
|
|
532
|
-
* You're not running short on RAM
|
|
352
|
+
#### Persistence
|
|
533
353
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
* You like numeric priorities
|
|
537
|
-
* You're not doing a gigantic amount of jobs each day
|
|
538
|
-
* Your queue stays small and nimble
|
|
539
|
-
* There is not a lot failure / chaos
|
|
540
|
-
* You want to easily throw anything on the queue
|
|
541
|
-
* You don't want to setup Redis
|
|
542
|
-
|
|
543
|
-
In no way is Resque a "better" DelayedJob, so make sure you pick the
|
|
544
|
-
tool that's best for your app.
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
Installing Redis
|
|
548
|
-
----------------
|
|
549
|
-
|
|
550
|
-
Resque requires Redis 0.900 or higher.
|
|
551
|
-
|
|
552
|
-
Resque uses Redis' lists for its queues. It also stores worker state
|
|
553
|
-
data in Redis.
|
|
554
|
-
|
|
555
|
-
#### Homebrew
|
|
556
|
-
|
|
557
|
-
If you're on OS X, Homebrew is the simplest way to install Redis:
|
|
558
|
-
|
|
559
|
-
$ brew install redis
|
|
560
|
-
$ redis-server /usr/local/etc/redis.conf
|
|
561
|
-
|
|
562
|
-
You now have a Redis daemon running on 6379.
|
|
563
|
-
|
|
564
|
-
#### Via Resque
|
|
565
|
-
|
|
566
|
-
Resque includes Rake tasks (thanks to Ezra's redis-rb) that will
|
|
567
|
-
install and run Redis for you:
|
|
568
|
-
|
|
569
|
-
$ git clone git://github.com/defunkt/resque.git
|
|
570
|
-
$ cd resque
|
|
571
|
-
$ rake redis:install dtach:install
|
|
572
|
-
$ rake redis:start
|
|
573
|
-
|
|
574
|
-
Or, if you don't have admin access on your machine:
|
|
575
|
-
|
|
576
|
-
$ git clone git://github.com/defunkt/resque.git
|
|
577
|
-
$ cd resque
|
|
578
|
-
$ PREFIX=<your_prefix> rake redis:install dtach:install
|
|
579
|
-
$ rake redis:start
|
|
580
|
-
|
|
581
|
-
You now have Redis running on 6379. Wait a second then hit ctrl-\ to
|
|
582
|
-
detach and keep it running in the background.
|
|
583
|
-
|
|
584
|
-
The demo is probably the best way to figure out how to put the parts
|
|
585
|
-
together. But, it's not that hard.
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
Resque Dependencies
|
|
589
|
-
-------------------
|
|
590
|
-
|
|
591
|
-
$ gem install bundler
|
|
592
|
-
$ bundle install
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
Installing Resque
|
|
596
|
-
-----------------
|
|
597
|
-
|
|
598
|
-
### In a Rack app, as a gem
|
|
599
|
-
|
|
600
|
-
First install the gem.
|
|
601
|
-
|
|
602
|
-
$ gem install resque
|
|
603
|
-
|
|
604
|
-
Next include it in your application.
|
|
354
|
+
Jobs are persisted to queues as JSON objects. Let's take our `Archive`
|
|
355
|
+
example from above. We'll run the following code to create a job:
|
|
605
356
|
|
|
606
357
|
``` ruby
|
|
607
|
-
|
|
358
|
+
repo = Repository.find(44)
|
|
359
|
+
repo.async_create_archive('masterbrew')
|
|
608
360
|
```
|
|
609
361
|
|
|
610
|
-
|
|
362
|
+
The following JSON will be stored in the `file_serve` queue:
|
|
611
363
|
|
|
612
|
-
|
|
364
|
+
``` javascript
|
|
365
|
+
{
|
|
366
|
+
'class': 'Archive',
|
|
367
|
+
'args': [ 44, 'masterbrew' ]
|
|
368
|
+
}
|
|
369
|
+
```
|
|
613
370
|
|
|
614
|
-
|
|
371
|
+
Because of this your jobs must only accept arguments that can be JSON encoded.
|
|
615
372
|
|
|
616
|
-
|
|
617
|
-
to an existing Rakefile):
|
|
373
|
+
So instead of doing this:
|
|
618
374
|
|
|
619
375
|
``` ruby
|
|
620
|
-
|
|
621
|
-
require 'resque/tasks'
|
|
376
|
+
Resque.enqueue(Archive, self, branch)
|
|
622
377
|
```
|
|
623
378
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
$ QUEUE=* rake resque:work
|
|
627
|
-
|
|
628
|
-
Alternately you can define a `resque:setup` hook in your Rakefile if you
|
|
629
|
-
don't want to load your app every time rake runs.
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
### In a Rails 2.x app, as a gem
|
|
633
|
-
|
|
634
|
-
First install the gem.
|
|
635
|
-
|
|
636
|
-
$ gem install resque
|
|
637
|
-
|
|
638
|
-
Next include it in your application.
|
|
639
|
-
|
|
640
|
-
$ cat config/initializers/load_resque.rb
|
|
641
|
-
require 'resque'
|
|
642
|
-
|
|
643
|
-
Now start your application:
|
|
644
|
-
|
|
645
|
-
$ ./script/server
|
|
646
|
-
|
|
647
|
-
That's it! You can now create Resque jobs from within your app.
|
|
648
|
-
|
|
649
|
-
To start a worker, add this to your Rakefile in `RAILS_ROOT`:
|
|
379
|
+
do this:
|
|
650
380
|
|
|
651
381
|
``` ruby
|
|
652
|
-
|
|
382
|
+
Resque.enqueue(Archive, self.id, branch)
|
|
653
383
|
```
|
|
654
384
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
$ QUEUE=* rake environment resque:work
|
|
385
|
+
This is why our above example (and all the examples in `examples/`)
|
|
386
|
+
uses object IDs instead of passing around the objects.
|
|
658
387
|
|
|
659
|
-
|
|
660
|
-
|
|
388
|
+
While this is less convenient than just sticking a marshaled object
|
|
389
|
+
in the database, it gives you a slight advantage: your jobs will be
|
|
390
|
+
run against the most recent version of an object because they need to
|
|
391
|
+
pull from the DB or cache.
|
|
661
392
|
|
|
393
|
+
If your jobs were run against marshaled objects, they could
|
|
394
|
+
potentially be operating on a stale record with out-of-date information.
|
|
662
395
|
|
|
663
|
-
### In a Rails 2.x app, as a plugin
|
|
664
396
|
|
|
665
|
-
|
|
397
|
+
#### send_later / async
|
|
666
398
|
|
|
667
|
-
|
|
668
|
-
|
|
399
|
+
Want something like DelayedJob's `send_later` or the ability to use
|
|
400
|
+
instance methods instead of just methods for jobs? See the `examples/`
|
|
401
|
+
directory for goodies.
|
|
669
402
|
|
|
670
|
-
|
|
403
|
+
We plan to provide first class `async` support in a future release.
|
|
671
404
|
|
|
672
|
-
$ QUEUE=* rake environment resque:work
|
|
673
405
|
|
|
674
|
-
|
|
675
|
-
`lib/tasks/whatever.rake` that loads the `environment` task every time.
|
|
406
|
+
#### Failure
|
|
676
407
|
|
|
408
|
+
If a job raises an exception, it is logged and handed off to the
|
|
409
|
+
`Resque::Failure` module. Failures are logged either locally in Redis
|
|
410
|
+
or using some different backend. To see exceptions while developing,
|
|
411
|
+
see details below under Logging.
|
|
677
412
|
|
|
678
|
-
|
|
413
|
+
For example, Resque ships with Airbrake support. To configure it, put
|
|
414
|
+
the following into an initialisation file or into your rake job:
|
|
679
415
|
|
|
680
|
-
|
|
416
|
+
``` ruby
|
|
417
|
+
# send errors which occur in background jobs to redis and airbrake
|
|
418
|
+
require 'resque/failure/multiple'
|
|
419
|
+
require 'resque/failure/redis'
|
|
420
|
+
require 'resque/failure/airbrake'
|
|
681
421
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
...
|
|
422
|
+
Resque::Failure::Multiple.classes = [Resque::Failure::Redis, Resque::Failure::Airbrake]
|
|
423
|
+
Resque::Failure.backend = Resque::Failure::Multiple
|
|
424
|
+
```
|
|
686
425
|
|
|
687
|
-
|
|
426
|
+
Keep this in mind when writing your jobs: you may want to throw
|
|
427
|
+
exceptions you would not normally throw in order to assist debugging.
|
|
688
428
|
|
|
689
|
-
$ bundle install
|
|
690
429
|
|
|
691
|
-
|
|
430
|
+
#### Rails example
|
|
692
431
|
|
|
693
|
-
|
|
432
|
+
If you are using ActiveJob here's how your job definition will look:
|
|
694
433
|
|
|
695
|
-
|
|
434
|
+
``` ruby
|
|
435
|
+
class ArchiveJob < ApplicationJob
|
|
436
|
+
queue_as :file_serve
|
|
696
437
|
|
|
697
|
-
|
|
698
|
-
|
|
438
|
+
def perform(repo_id, branch = 'master')
|
|
439
|
+
repo = Repository.find(repo_id)
|
|
440
|
+
repo.create_archive(branch)
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
```
|
|
699
444
|
|
|
700
445
|
``` ruby
|
|
701
|
-
|
|
446
|
+
class Repository
|
|
447
|
+
def async_create_archive(branch)
|
|
448
|
+
ArchiveJob.perform_later(self.id, branch)
|
|
449
|
+
end
|
|
450
|
+
end
|
|
702
451
|
```
|
|
703
452
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
Don't forget you can define a `resque:setup` hook in
|
|
709
|
-
`lib/tasks/whatever.rake` that loads the `environment` task every time.
|
|
453
|
+
It is important to run `ArchiveJob.perform_later(self.id, branch)` rather than `Resque.enqueue(Archive, self.id, branch)`.
|
|
454
|
+
Otherwise Resque will process the job without actually doing anything.
|
|
455
|
+
Even if you put an obviously buggy line like `0/0` in the `perform` method,
|
|
456
|
+
the job will still succeed.
|
|
710
457
|
|
|
711
458
|
|
|
712
459
|
Configuration
|
|
713
460
|
-------------
|
|
714
461
|
|
|
462
|
+
#### Redis
|
|
463
|
+
|
|
715
464
|
You may want to change the Redis host and port Resque connects to, or
|
|
716
465
|
set various other options at startup.
|
|
717
466
|
|
|
@@ -733,15 +482,16 @@ Here's our `config/resque.yml`:
|
|
|
733
482
|
test: localhost:6379
|
|
734
483
|
staging: redis1.se.github.com:6379
|
|
735
484
|
fi: localhost:6379
|
|
736
|
-
production:
|
|
485
|
+
production: <%= ENV['REDIS_URL'] %>
|
|
737
486
|
|
|
738
487
|
And our initializer:
|
|
739
488
|
|
|
740
489
|
``` ruby
|
|
741
490
|
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
|
|
742
491
|
rails_env = ENV['RAILS_ENV'] || 'development'
|
|
492
|
+
config_file = rails_root + '/config/resque.yml'
|
|
743
493
|
|
|
744
|
-
resque_config = YAML.
|
|
494
|
+
resque_config = YAML::load(ERB.new(IO.read(config_file)).result)
|
|
745
495
|
Resque.redis = resque_config[rails_env]
|
|
746
496
|
```
|
|
747
497
|
|
|
@@ -759,26 +509,31 @@ For example, if you want to run all jobs in the same process for cucumber, try:
|
|
|
759
509
|
Resque.inline = ENV['RAILS_ENV'] == "cucumber"
|
|
760
510
|
```
|
|
761
511
|
|
|
512
|
+
#### Logging
|
|
762
513
|
|
|
763
|
-
|
|
764
|
-
-----------------
|
|
514
|
+
Workers support basic logging to STDOUT.
|
|
765
515
|
|
|
766
|
-
|
|
767
|
-
<http://wiki.github.com/defunkt/resque/plugins>.
|
|
516
|
+
You can control the logging threshold using `Resque.logger.level`:
|
|
768
517
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
518
|
+
```ruby
|
|
519
|
+
# config/initializers/resque.rb
|
|
520
|
+
Resque.logger.level = Logger::DEBUG
|
|
521
|
+
```
|
|
772
522
|
|
|
523
|
+
If you want Resque to log to a file, in Rails do:
|
|
773
524
|
|
|
774
|
-
|
|
775
|
-
|
|
525
|
+
```ruby
|
|
526
|
+
# config/initializers/resque.rb
|
|
527
|
+
Resque.logger = Logger.new(Rails.root.join('log', "#{Rails.env}_resque.log"))
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
#### Namespaces
|
|
776
531
|
|
|
777
532
|
If you're running multiple, separate instances of Resque you may want
|
|
778
533
|
to namespace the keyspaces so they do not overlap. This is not unlike
|
|
779
534
|
the approach taken by many memcached clients.
|
|
780
535
|
|
|
781
|
-
This feature is provided by the [redis-namespace]
|
|
536
|
+
This feature is provided by the [redis-namespace](http://github.com/resque/redis-namespace) library, which
|
|
782
537
|
Resque uses by default to separate the keys it manages from other keys
|
|
783
538
|
in your Redis server.
|
|
784
539
|
|
|
@@ -791,38 +546,269 @@ Resque.redis.namespace = "resque:GitHub"
|
|
|
791
546
|
We recommend sticking this in your initializer somewhere after Redis
|
|
792
547
|
is configured.
|
|
793
548
|
|
|
549
|
+
#### Storing Statistics
|
|
550
|
+
Resque allows to store count of processed and failed jobs.
|
|
794
551
|
|
|
795
|
-
|
|
796
|
-
----
|
|
552
|
+
By default it will store it in Redis using the keys `stats:processed` and `stats:failed`.
|
|
797
553
|
|
|
798
|
-
|
|
799
|
-
processed in the background.
|
|
554
|
+
Some apps would want another stats store, or even a null store:
|
|
800
555
|
|
|
801
|
-
|
|
556
|
+
```ruby
|
|
557
|
+
# config/initializers/resque.rb
|
|
558
|
+
class NullDataStore
|
|
559
|
+
def stat(stat)
|
|
560
|
+
0
|
|
561
|
+
end
|
|
802
562
|
|
|
563
|
+
def increment_stat(stat, by)
|
|
564
|
+
end
|
|
803
565
|
|
|
804
|
-
|
|
805
|
-
|
|
566
|
+
def decrement_stat(stat, by)
|
|
567
|
+
end
|
|
806
568
|
|
|
807
|
-
|
|
569
|
+
def clear_stat(stat)
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
Resque.stat_data_store = NullDataStore.new
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Plugins and Hooks
|
|
577
|
+
-----------------
|
|
578
|
+
|
|
579
|
+
For a list of available plugins see
|
|
580
|
+
<https://github.com/resque/resque/wiki/plugins>.
|
|
581
|
+
|
|
582
|
+
If you'd like to write your own plugin, or want to customize Resque
|
|
583
|
+
using hooks (such as `Resque.after_fork`), see
|
|
584
|
+
[docs/HOOKS.md](http://github.com/resque/resque/blob/master/docs/HOOKS.md).
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
Additional Information
|
|
588
|
+
----------------------
|
|
589
|
+
|
|
590
|
+
#### Resque vs DelayedJob
|
|
591
|
+
|
|
592
|
+
How does Resque compare to DelayedJob, and why would you choose one
|
|
593
|
+
over the other?
|
|
594
|
+
|
|
595
|
+
* Resque supports multiple queues
|
|
596
|
+
* DelayedJob supports finer grained priorities
|
|
597
|
+
* Resque workers are resilient to memory leaks / bloat
|
|
598
|
+
* DelayedJob workers are extremely simple and easy to modify
|
|
599
|
+
* Resque requires Redis
|
|
600
|
+
* DelayedJob requires ActiveRecord
|
|
601
|
+
* Resque can only place JSONable Ruby objects on a queue as arguments
|
|
602
|
+
* DelayedJob can place _any_ Ruby object on its queue as arguments
|
|
603
|
+
* Resque includes a Sinatra app for monitoring what's going on
|
|
604
|
+
* DelayedJob can be queried from within your Rails app if you want to
|
|
605
|
+
add an interface
|
|
606
|
+
|
|
607
|
+
If you're doing Rails development, you already have a database and
|
|
608
|
+
ActiveRecord. DelayedJob is super easy to setup and works great.
|
|
609
|
+
GitHub used it for many months to process almost 200 million jobs.
|
|
610
|
+
|
|
611
|
+
Choose Resque if:
|
|
612
|
+
|
|
613
|
+
* You need multiple queues
|
|
614
|
+
* You don't care / dislike numeric priorities
|
|
615
|
+
* You don't need to persist every Ruby object ever
|
|
616
|
+
* You have potentially huge queues
|
|
617
|
+
* You want to see what's going on
|
|
618
|
+
* You expect a lot of failure / chaos
|
|
619
|
+
* You can setup Redis
|
|
620
|
+
* You're not running short on RAM
|
|
621
|
+
|
|
622
|
+
Choose DelayedJob if:
|
|
623
|
+
|
|
624
|
+
* You like numeric priorities
|
|
625
|
+
* You're not doing a gigantic amount of jobs each day
|
|
626
|
+
* Your queue stays small and nimble
|
|
627
|
+
* There is not a lot failure / chaos
|
|
628
|
+
* You want to easily throw anything on the queue
|
|
629
|
+
* You don't want to setup Redis
|
|
630
|
+
|
|
631
|
+
In no way is Resque a "better" DelayedJob, so make sure you pick the
|
|
632
|
+
tool that's best for your app.
|
|
633
|
+
|
|
634
|
+
#### Forking
|
|
635
|
+
|
|
636
|
+
On certain platforms, when a Resque worker reserves a job it
|
|
637
|
+
immediately forks a child process. The child processes the job then
|
|
638
|
+
exits. When the child has exited successfully, the worker reserves
|
|
639
|
+
another job and repeats the process.
|
|
640
|
+
|
|
641
|
+
Why?
|
|
642
|
+
|
|
643
|
+
Because Resque assumes chaos.
|
|
644
|
+
|
|
645
|
+
Resque assumes your background workers will lock up, run too long, or
|
|
646
|
+
have unwanted memory growth.
|
|
647
|
+
|
|
648
|
+
If Resque workers processed jobs themselves, it'd be hard to whip them
|
|
649
|
+
into shape. Let's say one is using too much memory: you send it a
|
|
650
|
+
signal that says "shutdown after you finish processing the current
|
|
651
|
+
job," and it does so. It then starts up again - loading your entire
|
|
652
|
+
application environment. This adds useless CPU cycles and causes a
|
|
653
|
+
delay in queue processing.
|
|
654
|
+
|
|
655
|
+
Plus, what if it's using too much memory and has stopped responding to
|
|
656
|
+
signals?
|
|
657
|
+
|
|
658
|
+
Thanks to Resque's parent / child architecture, jobs that use too much memory
|
|
659
|
+
release that memory upon completion. No unwanted growth.
|
|
660
|
+
|
|
661
|
+
And what if a job is running too long? You'd need to `kill -9` it then
|
|
662
|
+
start the worker again. With Resque's parent / child architecture you
|
|
663
|
+
can tell the parent to forcefully kill the child then immediately
|
|
664
|
+
start processing more jobs. No startup delay or wasted cycles.
|
|
665
|
+
|
|
666
|
+
The parent / child architecture helps us keep tabs on what workers are
|
|
667
|
+
doing, too. By eliminating the need to `kill -9` workers we can have
|
|
668
|
+
parents remove themselves from the global listing of workers. If we
|
|
669
|
+
just ruthlessly killed workers, we'd need a separate watchdog process
|
|
670
|
+
to add and remove them to the global listing - which becomes
|
|
671
|
+
complicated.
|
|
672
|
+
|
|
673
|
+
Workers instead handle their own state.
|
|
674
|
+
|
|
675
|
+
#### `at_exit` Callbacks
|
|
676
|
+
|
|
677
|
+
Resque uses `Kernel#exit!` for exiting its workers' child processes. So any `at_exit` callback defined in your application won't be executed when the job is finished and the child process exits.
|
|
678
|
+
|
|
679
|
+
You can alter this behavior by setting the `RUN_AT_EXIT_HOOKS` environment variable.
|
|
680
|
+
|
|
681
|
+
#### Parents and Children
|
|
682
|
+
|
|
683
|
+
Here's a parent / child pair doing some work:
|
|
684
|
+
|
|
685
|
+
$ ps -e -o pid,command | grep [r]esque
|
|
686
|
+
92099 resque: Forked 92102 at 1253142769
|
|
687
|
+
92102 resque: Processing file_serve since 1253142769
|
|
688
|
+
|
|
689
|
+
You can clearly see that process 92099 forked 92102, which has been
|
|
690
|
+
working since 1253142769.
|
|
691
|
+
|
|
692
|
+
(By advertising the time they began processing you can easily use monit
|
|
693
|
+
or god to kill stale workers.)
|
|
694
|
+
|
|
695
|
+
When a parent process is idle, it lets you know what queues it is
|
|
696
|
+
waiting for work on:
|
|
697
|
+
|
|
698
|
+
$ ps -e -o pid,command | grep [r]esque
|
|
699
|
+
92099 resque: Waiting for file_serve,warm_cache
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
#### Signals
|
|
703
|
+
|
|
704
|
+
Resque workers respond to a few different signals:
|
|
705
|
+
|
|
706
|
+
* `QUIT` - Wait for child to finish processing then exit
|
|
707
|
+
* `TERM` / `INT` - Immediately kill child then exit
|
|
708
|
+
* `USR1` - Immediately kill child but don't exit
|
|
709
|
+
* `USR2` - Don't start to process any new jobs
|
|
710
|
+
* `CONT` - Start to process new jobs again after a USR2
|
|
711
|
+
|
|
712
|
+
If you want to gracefully shutdown a Resque worker, use `QUIT`.
|
|
713
|
+
|
|
714
|
+
If you want to kill a stale or stuck child, use `USR1`. Processing
|
|
715
|
+
will continue as normal unless the child was not found. In that case
|
|
716
|
+
Resque assumes the parent process is in a bad state and shuts down.
|
|
717
|
+
|
|
718
|
+
If you want to kill a stale or stuck child and shutdown, use `TERM`
|
|
719
|
+
|
|
720
|
+
If you want to stop processing jobs, but want to leave the worker running
|
|
721
|
+
(for example, to temporarily alleviate load), use `USR2` to stop processing,
|
|
722
|
+
then `CONT` to start it again. It's also possible to [pause all workers](#pausing-all-workers).
|
|
723
|
+
|
|
724
|
+
#### Heroku
|
|
725
|
+
|
|
726
|
+
When shutting down processes, Heroku sends every process a TERM signal at the
|
|
727
|
+
same time. By default this causes an immediate shutdown of any running job
|
|
728
|
+
leading to frequent `Resque::TermException` errors. For short running jobs, a simple
|
|
729
|
+
solution is to give a small amount of time for the job to finish
|
|
730
|
+
before killing it.
|
|
731
|
+
|
|
732
|
+
Resque doesn't handle this out of the box (for both cedar-14 and heroku-16), you need to
|
|
733
|
+
install the [`resque-heroku-signals`](https://github.com/iloveitaly/resque-heroku-signals)
|
|
734
|
+
addon which adds the required signal handling to make the behavior described above work.
|
|
735
|
+
Related issue: https://github.com/resque/resque/issues/1559
|
|
736
|
+
|
|
737
|
+
To accomplish this set the following environment variables:
|
|
738
|
+
|
|
739
|
+
* `RESQUE_PRE_SHUTDOWN_TIMEOUT` - The time between the parent receiving a shutdown signal (TERM by default) and it sending that signal on to the child process. Designed to give the child process
|
|
740
|
+
time to complete before being forced to die.
|
|
741
|
+
|
|
742
|
+
* `TERM_CHILD` - Must be set for `RESQUE_PRE_SHUTDOWN_TIMEOUT` to be used. After the timeout, if the child is still running it will raise a `Resque::TermException` and exit.
|
|
743
|
+
|
|
744
|
+
* `RESQUE_TERM_TIMEOUT` - By default you have a few seconds to handle `Resque::TermException` in your job. `RESQUE_TERM_TIMEOUT` and `RESQUE_PRE_SHUTDOWN_TIMEOUT` must be lower than the [heroku dyno timeout](https://devcenter.heroku.com/articles/limits#exit-timeout).
|
|
745
|
+
|
|
746
|
+
#### Pausing all workers
|
|
747
|
+
|
|
748
|
+
Workers will not process pending jobs if the Redis key `pause-all-workers` is set with the string value "true".
|
|
749
|
+
|
|
750
|
+
``` ruby
|
|
751
|
+
Resque.redis.set('pause-all-workers', 'true')
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
Nothing happens to jobs that are already being processed by workers.
|
|
755
|
+
|
|
756
|
+
Unpause by removing the Redis key `pause-all-workers`.
|
|
757
|
+
|
|
758
|
+
``` ruby
|
|
759
|
+
Resque.redis.del('pause-all-workers')
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
#### Monitoring
|
|
763
|
+
|
|
764
|
+
##### god
|
|
808
765
|
|
|
809
766
|
If you're using god to monitor Resque, we have provided example
|
|
810
767
|
configs in `examples/god/`. One is for starting / stopping workers,
|
|
811
768
|
the other is for killing workers that have been running too long.
|
|
812
769
|
|
|
813
|
-
|
|
770
|
+
##### monit
|
|
814
771
|
|
|
815
772
|
If you're using monit, `examples/monit/resque.monit` is provided free
|
|
816
773
|
of charge. This is **not** used by GitHub in production, so please
|
|
817
774
|
send patches for any tweaks or improvements you can make to it.
|
|
818
775
|
|
|
776
|
+
#### Mysql::Error: MySQL server has gone away
|
|
819
777
|
|
|
820
|
-
|
|
821
|
-
---------
|
|
778
|
+
If your workers remain idle for too long they may lose their MySQL connection. Depending on your version of Rails, we recommend the following:
|
|
822
779
|
|
|
823
|
-
|
|
824
|
-
|
|
780
|
+
##### Rails
|
|
781
|
+
In your `perform` method, add the following line:
|
|
825
782
|
|
|
783
|
+
``` ruby
|
|
784
|
+
class MyTask
|
|
785
|
+
def self.perform
|
|
786
|
+
ActiveRecord::Base.verify_active_connections!
|
|
787
|
+
# rest of your code
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
The Rails doc says the following about `verify_active_connections!`:
|
|
793
|
+
|
|
794
|
+
Verify active connections and remove and disconnect connections associated with stale threads.
|
|
795
|
+
|
|
796
|
+
##### Rails 4.x
|
|
797
|
+
|
|
798
|
+
In your `perform` method, instead of `verify_active_connections!`, use:
|
|
799
|
+
|
|
800
|
+
``` ruby
|
|
801
|
+
class MyTask
|
|
802
|
+
def self.perform
|
|
803
|
+
ActiveRecord::Base.clear_active_connections!
|
|
804
|
+
# rest of your code
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
From the Rails docs on [`clear_active_connections!`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionHandler.html#method-i-clear_active_connections-21):
|
|
810
|
+
|
|
811
|
+
Returns any connections in use by the current thread back to the pool, and also returns connections to the pool cached by threads that are no longer alive.
|
|
826
812
|
|
|
827
813
|
Development
|
|
828
814
|
-----------
|
|
@@ -831,7 +817,7 @@ Want to hack on Resque?
|
|
|
831
817
|
|
|
832
818
|
First clone the repo and run the tests:
|
|
833
819
|
|
|
834
|
-
git clone git://github.com/
|
|
820
|
+
git clone git://github.com/resque/resque.git
|
|
835
821
|
cd resque
|
|
836
822
|
rake test
|
|
837
823
|
|
|
@@ -853,56 +839,40 @@ it:
|
|
|
853
839
|
If you get an error requiring any of the dependencies, you may have
|
|
854
840
|
failed to install them or be seeing load path issues.
|
|
855
841
|
|
|
856
|
-
|
|
857
|
-
|
|
842
|
+
#### Demo
|
|
843
|
+
Resque ships with a demo Sinatra app for creating jobs that are later
|
|
844
|
+
processed in the background.
|
|
858
845
|
|
|
846
|
+
Try it out by looking at the README, found at `examples/demo/README.markdown`.
|
|
859
847
|
|
|
860
|
-
Contributing
|
|
861
|
-
------------
|
|
848
|
+
#### Contributing
|
|
862
849
|
|
|
863
|
-
Read
|
|
850
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) first.
|
|
864
851
|
|
|
865
852
|
Once you've made your great commits:
|
|
866
853
|
|
|
867
|
-
1. [Fork]
|
|
854
|
+
1. [Fork](http://help.github.com/forking/) Resque
|
|
868
855
|
2. Create a topic branch - `git checkout -b my_branch`
|
|
869
856
|
3. Push to your branch - `git push origin my_branch`
|
|
870
857
|
4. Create a [Pull Request](http://help.github.com/pull-requests/) from your branch
|
|
871
|
-
5. That's it!
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
Mailing List
|
|
875
|
-
------------
|
|
876
|
-
|
|
877
|
-
To join the list simply send an email to <resque@librelist.com>. This
|
|
878
|
-
will subscribe you and send you information about your subscription,
|
|
879
|
-
including unsubscribe information.
|
|
880
858
|
|
|
881
|
-
|
|
859
|
+
Questions
|
|
860
|
+
---------
|
|
882
861
|
|
|
862
|
+
Please add them to the [FAQ](https://github.com/resque/resque/wiki/FAQ) or open an issue on this repo.
|
|
883
863
|
|
|
884
864
|
Meta
|
|
885
865
|
----
|
|
886
866
|
|
|
887
|
-
* Code: `git clone git://github.com/
|
|
888
|
-
* Home: <http://github.com/
|
|
889
|
-
* Docs: <http://
|
|
890
|
-
* Bugs: <http://github.com/
|
|
891
|
-
*
|
|
892
|
-
* Chat: <irc://irc.freenode.net/resque>
|
|
893
|
-
* Gems: <http://gemcutter.org/gems/resque>
|
|
894
|
-
|
|
895
|
-
This project uses [Semantic Versioning][sv].
|
|
867
|
+
* Code: `git clone git://github.com/resque/resque.git`
|
|
868
|
+
* Home: <http://github.com/resque/resque>
|
|
869
|
+
* Docs: <http://rubydoc.info/gems/resque>
|
|
870
|
+
* Bugs: <http://github.com/resque/resque/issues>
|
|
871
|
+
* Gems: <https://rubygems.org/gems/resque>
|
|
896
872
|
|
|
873
|
+
This project uses [Semantic Versioning](http://semver.org/)
|
|
897
874
|
|
|
898
875
|
Author
|
|
899
876
|
------
|
|
900
877
|
|
|
901
878
|
Chris Wanstrath :: chris@ozmm.org :: @defunkt
|
|
902
|
-
|
|
903
|
-
[0]: http://github.com/blog/542-introducing-resque
|
|
904
|
-
[1]: http://help.github.com/forking/
|
|
905
|
-
[2]: http://github.com/defunkt/resque/issues
|
|
906
|
-
[sv]: http://semver.org/
|
|
907
|
-
[rs]: http://github.com/defunkt/redis-namespace
|
|
908
|
-
[cb]: http://wiki.github.com/defunkt/resque/contributing
|