resque 1.23.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +271 -0
  3. data/README.markdown +454 -484
  4. data/Rakefile +4 -17
  5. data/bin/resque-web +10 -22
  6. data/lib/resque/data_store.rb +335 -0
  7. data/lib/resque/errors.rb +15 -1
  8. data/lib/resque/failure/airbrake.rb +32 -4
  9. data/lib/resque/failure/base.rb +16 -7
  10. data/lib/resque/failure/multiple.rb +26 -8
  11. data/lib/resque/failure/redis.rb +92 -15
  12. data/lib/resque/failure/redis_multi_queue.rb +104 -0
  13. data/lib/resque/failure.rb +62 -32
  14. data/lib/resque/helpers.rb +11 -57
  15. data/lib/resque/job.rb +79 -12
  16. data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
  17. data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
  18. data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
  19. data/lib/resque/logging.rb +18 -0
  20. data/lib/resque/plugin.rb +22 -10
  21. data/lib/resque/railtie.rb +10 -0
  22. data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
  23. data/lib/resque/server/public/jquery.relatize_date.js +4 -4
  24. data/lib/resque/server/public/main.js +3 -0
  25. data/lib/resque/server/public/ranger.js +16 -8
  26. data/lib/resque/server/public/style.css +13 -8
  27. data/lib/resque/server/views/error.erb +1 -1
  28. data/lib/resque/server/views/failed.erb +27 -59
  29. data/lib/resque/server/views/failed_job.erb +50 -0
  30. data/lib/resque/server/views/failed_queues_overview.erb +24 -0
  31. data/lib/resque/server/views/job_class.erb +8 -0
  32. data/lib/resque/server/views/key_sets.erb +2 -4
  33. data/lib/resque/server/views/key_string.erb +1 -1
  34. data/lib/resque/server/views/layout.erb +7 -6
  35. data/lib/resque/server/views/next_more.erb +22 -10
  36. data/lib/resque/server/views/processing.erb +2 -0
  37. data/lib/resque/server/views/queues.erb +22 -13
  38. data/lib/resque/server/views/stats.erb +5 -5
  39. data/lib/resque/server/views/workers.erb +4 -4
  40. data/lib/resque/server/views/working.erb +10 -11
  41. data/lib/resque/server.rb +51 -108
  42. data/lib/resque/server_helper.rb +185 -0
  43. data/lib/resque/stat.rb +19 -7
  44. data/lib/resque/tasks.rb +26 -25
  45. data/lib/resque/thread_signal.rb +24 -0
  46. data/lib/resque/vendor/utf8_util.rb +2 -8
  47. data/lib/resque/version.rb +1 -1
  48. data/lib/resque/web_runner.rb +374 -0
  49. data/lib/resque/worker.rb +487 -163
  50. data/lib/resque.rb +332 -52
  51. data/lib/tasks/redis.rake +11 -11
  52. metadata +169 -149
  53. data/lib/resque/failure/hoptoad.rb +0 -33
  54. data/lib/resque/failure/thoughtbot.rb +0 -33
  55. data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
  56. data/lib/resque/server/test_helper.rb +0 -19
  57. data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
  58. data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
  59. data/test/airbrake_test.rb +0 -27
  60. data/test/hoptoad_test.rb +0 -26
  61. data/test/job_hooks_test.rb +0 -464
  62. data/test/job_plugins_test.rb +0 -230
  63. data/test/plugin_test.rb +0 -116
  64. data/test/redis-test-cluster.conf +0 -115
  65. data/test/redis-test.conf +0 -115
  66. data/test/resque-web_test.rb +0 -59
  67. data/test/resque_failure_redis_test.rb +0 -19
  68. data/test/resque_test.rb +0 -278
  69. data/test/test_helper.rb +0 -178
  70. data/test/worker_test.rb +0 -657
data/README.markdown CHANGED
@@ -1,10 +1,18 @@
1
1
  Resque
2
2
  ======
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/resque.svg)](https://rubygems.org/gems/resque)
5
+ [![Build Status](https://github.com/resque/resque/actions/workflows/ci.yml/badge.svg)](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 distributed between multiple machines,
21
- support priorities, are resilient to memory bloat / "leaks," are
22
- optimized for REE (but work on MRI and JRuby), tell you what they're
23
- doing, and expect failure.
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
- The Blog Post
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
- Overview
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
- Workers can be given multiple queues (a "queue list") and run on
106
- multiple machines. In fact they can be run anywhere with network
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
- * Warming caches
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
- As of writing we have about 35 different types of background jobs.
118
+ gem 'resque'
129
119
 
130
- Keep in mind that you don't need a web app to use Resque - we just
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
- ### Persistence
124
+ #### Rack
137
125
 
138
- Jobs are persisted to queues as JSON objects. Let's take our `Archive`
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
- repo = Repository.find(44)
143
- repo.async_create_archive('masterbrew')
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
- Because of this your jobs must only accept arguments that can be JSON encoded.
156
-
157
- So instead of doing this:
158
-
159
- ``` ruby
160
- Resque.enqueue(Archive, self, branch)
161
- ```
134
+ #### Rails
162
135
 
163
- do this:
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
- Resque.enqueue(Archive, self.id, branch)
139
+ task "resque:setup" => :environment do
140
+ Grit::Git.git_timeout = 10.minutes
141
+ end
167
142
  ```
168
143
 
169
- This is why our above example (and all the examples in `examples/`)
170
- uses object IDs instead of passing around the objects.
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. Here's our example from earlier:
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
- Workers support basic logging to STDOUT. If you start them with the
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
- ### Polling frequency
168
+ Or, you can start multiple workers:
279
169
 
280
- You can pass an INTERVAL option which is a float representing the polling frequency.
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
- $ INTERVAL=0.1 QUEUE=file_serve rake environment resque:work
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
- ### Priorities and Queue Lists
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
- ### Running Multiple Workers
220
+ # QUEUE=critical,* rake resque:work
331
221
 
332
- At GitHub we use god to start and stop multiple workers. A sample god
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'd like to run multiple workers in development mode, you can do
337
- so using the `resque:workers` rake task:
224
+ If you want your workers to work off of all queues except for some,
225
+ you can use negation:
338
226
 
339
- $ COUNT=5 QUEUE=* rake resque:workers
227
+ $ QUEUE=*,!low rake resque:work
340
228
 
341
- This will spawn five Resque workers, each in its own thread. Hitting
342
- ctrl-c should be sufficient to stop them all.
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
- When a parent process is idle, it lets you know what queues it is
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
- ### Signals
238
+ #### Process IDs (PIDs)
409
239
 
410
- Resque workers respond to a few different signals:
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
- * `QUIT` - Wait for child to finish processing then exit
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
- If you want to gracefully shutdown a Resque worker, use `QUIT`.
245
+ #### Running in the background
419
246
 
420
- If you want to kill a stale or stuck child, use `USR1`. Processing
421
- will continue as normal unless the child was not found. In that case
422
- Resque assumes the parent process is in a bad state and shuts down.
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
- If you want to kill a stale or stuck child and shutdown, use `TERM`
252
+ $ PIDFILE=./resque.pid BACKGROUND=yes QUEUE=file_serve rake resque:work
425
253
 
426
- If you want to stop processing jobs, but want to leave the worker running
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
- ### Mysql::Error: MySQL server has gone away
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
- If your workers remain idle for too long they may lose their MySQL
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
- ![The Front End](https://img.skitch.com/20110528-pc67a8qsfapgjxf5gagxd92fcu.png)
270
+ ![The Front End](https://camo.githubusercontent.com/64d150a243987ffbc33f588bd6d7722a0bb8d69a/687474703a2f2f7475746f7269616c732e6a756d7073746172746c61622e636f6d2f696d616765732f7265737175655f6f766572766965772e706e67)
444
271
 
445
- ### Standalone
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
- ### Passenger
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: <http://www.modrails.com/documentation/Users%20guide%20Apache.html#_deploying_a_rack_based_ruby_application>
474
- Nginx: <http://www.modrails.com/documentation/Users%20guide%20Nginx.html#deploying_a_rack_app>
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
- ### Rack::URLMap
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
- ### Rails 3
319
+ #### Rails
493
320
 
494
- You can also mount Resque on a subpath in your existing Rails 3 app by adding `require 'resque/server'` to the top of your routes file or in an initializer then adding this to `routes.rb`:
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
- Resque vs DelayedJob
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
- How does Resque compare to DelayedJob, and why would you choose one
505
- over the other?
333
+ At GitHub we use Resque to process the following types of jobs:
506
334
 
507
- * Resque supports multiple queues
508
- * DelayedJob supports finer grained priorities
509
- * Resque workers are resilient to memory leaks / bloat
510
- * DelayedJob workers are extremely simple and easy to modify
511
- * Resque requires Redis
512
- * DelayedJob requires ActiveRecord
513
- * Resque can only place JSONable Ruby objects on a queue as arguments
514
- * DelayedJob can place _any_ Ruby object on its queue as arguments
515
- * Resque includes a Sinatra app for monitoring what's going on
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
- If you're doing Rails development, you already have a database and
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
- Choose Resque if:
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
- * You need multiple queues
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
- Choose DelayedJob if:
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
- require 'resque'
358
+ repo = Repository.find(44)
359
+ repo.async_create_archive('masterbrew')
608
360
  ```
609
361
 
610
- Now start your application:
362
+ The following JSON will be stored in the `file_serve` queue:
611
363
 
612
- rackup config.ru
364
+ ``` javascript
365
+ {
366
+ 'class': 'Archive',
367
+ 'args': [ 44, 'masterbrew' ]
368
+ }
369
+ ```
613
370
 
614
- That's it! You can now create Resque jobs from within your app.
371
+ Because of this your jobs must only accept arguments that can be JSON encoded.
615
372
 
616
- To start a worker, create a Rakefile in your app's root (or add this
617
- to an existing Rakefile):
373
+ So instead of doing this:
618
374
 
619
375
  ``` ruby
620
- require 'your/app'
621
- require 'resque/tasks'
376
+ Resque.enqueue(Archive, self, branch)
622
377
  ```
623
378
 
624
- Now:
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
- require 'resque/tasks'
382
+ Resque.enqueue(Archive, self.id, branch)
653
383
  ```
654
384
 
655
- Now:
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
- Don't forget you can define a `resque:setup` hook in
660
- `lib/tasks/whatever.rake` that loads the `environment` task every time.
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
- $ ./script/plugin install git://github.com/defunkt/resque
397
+ #### send_later / async
666
398
 
667
- That's it! Resque will automatically be available when your Rails app
668
- loads.
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
- To start a worker:
403
+ We plan to provide first class `async` support in a future release.
671
404
 
672
- $ QUEUE=* rake environment resque:work
673
405
 
674
- Don't forget you can define a `resque:setup` hook in
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
- ### In a Rails 3 app, as a gem
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
- First include it in your Gemfile.
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
- $ cat Gemfile
683
- ...
684
- gem 'resque'
685
- ...
422
+ Resque::Failure::Multiple.classes = [Resque::Failure::Redis, Resque::Failure::Airbrake]
423
+ Resque::Failure.backend = Resque::Failure::Multiple
424
+ ```
686
425
 
687
- Next install it with Bundler.
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
- Now start your application:
430
+ #### Rails example
692
431
 
693
- $ rails server
432
+ If you are using ActiveJob here's how your job definition will look:
694
433
 
695
- That's it! You can now create Resque jobs from within your app.
434
+ ``` ruby
435
+ class ArchiveJob < ApplicationJob
436
+ queue_as :file_serve
696
437
 
697
- To start a worker, add this to a file in `lib/tasks` (ex:
698
- `lib/tasks/resque.rake`):
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
- require 'resque/tasks'
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
- Now:
705
-
706
- $ QUEUE=* rake environment resque:work
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: redis1.ae.github.com:6379
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.load_file(rails_root + '/config/resque.yml')
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
- Plugins and Hooks
764
- -----------------
514
+ Workers support basic logging to STDOUT.
765
515
 
766
- For a list of available plugins see
767
- <http://wiki.github.com/defunkt/resque/plugins>.
516
+ You can control the logging threshold using `Resque.logger.level`:
768
517
 
769
- If you'd like to write your own plugin, or want to customize Resque
770
- using hooks (such as `Resque.after_fork`), see
771
- [docs/HOOKS.md](http://github.com/defunkt/resque/blob/master/docs/HOOKS.md).
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
- Namespaces
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][rs] library, which
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
- Demo
796
- ----
552
+ By default it will store it in Redis using the keys `stats:processed` and `stats:failed`.
797
553
 
798
- Resque ships with a demo Sinatra app for creating jobs that are later
799
- processed in the background.
554
+ Some apps would want another stats store, or even a null store:
800
555
 
801
- Try it out by looking at the README, found at `examples/demo/README.markdown`.
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
- Monitoring
805
- ----------
566
+ def decrement_stat(stat, by)
567
+ end
806
568
 
807
- ### god
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
- ### monit
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
- Questions
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
- Please add them to the [FAQ](https://github.com/defunkt/resque/wiki/FAQ) or
824
- ask on the Mailing List. The Mailing List is explained further below
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/defunkt/resque.git
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
- Feel free to ping the mailing list with your problem and we'll try to
857
- sort it out.
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 the [Contributing][cb] wiki page first.
850
+ Read [CONTRIBUTING.md](CONTRIBUTING.md) first.
864
851
 
865
852
  Once you've made your great commits:
866
853
 
867
- 1. [Fork][1] Resque
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
- The archive can be found at <http://librelist.com/browser/resque/>.
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/defunkt/resque.git`
888
- * Home: <http://github.com/defunkt/resque>
889
- * Docs: <http://defunkt.github.com/resque/>
890
- * Bugs: <http://github.com/defunkt/resque/issues>
891
- * List: <resque@librelist.com>
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