nfo-resque-mongo 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/HISTORY.md +259 -0
  2. data/LICENSE +20 -0
  3. data/README.markdown +828 -0
  4. data/Rakefile +73 -0
  5. data/bin/resque +75 -0
  6. data/bin/resque-web +23 -0
  7. data/lib/resque/errors.rb +10 -0
  8. data/lib/resque/failure/base.rb +74 -0
  9. data/lib/resque/failure/hoptoad.rb +139 -0
  10. data/lib/resque/failure/mongo.rb +92 -0
  11. data/lib/resque/failure/multiple.rb +60 -0
  12. data/lib/resque/failure.rb +82 -0
  13. data/lib/resque/helpers.rb +79 -0
  14. data/lib/resque/job.rb +228 -0
  15. data/lib/resque/plugin.rb +51 -0
  16. data/lib/resque/queue_stats.rb +58 -0
  17. data/lib/resque/server/public/idle.png +0 -0
  18. data/lib/resque/server/public/jquery-1.3.2.min.js +19 -0
  19. data/lib/resque/server/public/jquery.relatize_date.js +95 -0
  20. data/lib/resque/server/public/poll.png +0 -0
  21. data/lib/resque/server/public/ranger.js +73 -0
  22. data/lib/resque/server/public/reset.css +48 -0
  23. data/lib/resque/server/public/style.css +86 -0
  24. data/lib/resque/server/public/working.png +0 -0
  25. data/lib/resque/server/test_helper.rb +19 -0
  26. data/lib/resque/server/views/error.erb +1 -0
  27. data/lib/resque/server/views/failed.erb +75 -0
  28. data/lib/resque/server/views/key_sets.erb +19 -0
  29. data/lib/resque/server/views/key_string.erb +11 -0
  30. data/lib/resque/server/views/layout.erb +38 -0
  31. data/lib/resque/server/views/next_more.erb +19 -0
  32. data/lib/resque/server/views/overview.erb +4 -0
  33. data/lib/resque/server/views/queues.erb +49 -0
  34. data/lib/resque/server/views/stats.erb +62 -0
  35. data/lib/resque/server/views/workers.erb +109 -0
  36. data/lib/resque/server/views/working.erb +68 -0
  37. data/lib/resque/server.rb +222 -0
  38. data/lib/resque/stat.rb +55 -0
  39. data/lib/resque/tasks.rb +42 -0
  40. data/lib/resque/version.rb +3 -0
  41. data/lib/resque/worker.rb +524 -0
  42. data/lib/resque.rb +384 -0
  43. data/tasks/redis.rake +161 -0
  44. data/tasks/resque.rake +2 -0
  45. data/test/dump.rdb +0 -0
  46. data/test/job_hooks_test.rb +323 -0
  47. data/test/job_plugins_test.rb +230 -0
  48. data/test/plugin_test.rb +116 -0
  49. data/test/queue_stats_test.rb +57 -0
  50. data/test/redis-test.conf +115 -0
  51. data/test/resque-web_test.rb +48 -0
  52. data/test/resque_test.rb +256 -0
  53. data/test/test_helper.rb +151 -0
  54. data/test/worker_test.rb +356 -0
  55. metadata +166 -0
data/HISTORY.md ADDED
@@ -0,0 +1,259 @@
1
+ ## 1.15.0 (2011-03-18)
2
+
3
+ * Fallback to Redis.connect. Makes ENV variables and whatnot work.
4
+ * Fixed Sinatra 1.2 compatibility
5
+
6
+ ## 1.14.0 (2011-03-17)
7
+
8
+ * Sleep interval can now be a float
9
+ * Added Resque.inline to allow in-process performing of jobs (for testing)
10
+ * Fixed tests for Ruby 1.9.2
11
+ * Added Resque.validate(klass) to validate a Job
12
+ * Decode errors are no longer ignored to help debugging
13
+ * Web: Sinatra 1.2 compatibility
14
+ * Fixed after_enqueue hook to actually run in `Resque.enqueue`
15
+ * Fixed very_verbose timestamps to use 24 hour time (AM/PM wasn't included)
16
+ * Fixed monit example
17
+ * Fixed Worker#pid
18
+
19
+ ## 1.13.0 (2011-02-07)
20
+
21
+ * Depend on redis-namespace >= 0.10
22
+ * README tweaks
23
+ * Use thread_safe option when setting redis url
24
+ * Bugfix: worker pruning
25
+
26
+ ## 1.12.0 (2011-02-03)
27
+
28
+ * Added pidfile writing from `rake resque:work`
29
+ * Added Worker#pid method
30
+ * Added configurable location for `rake install`
31
+ * Bugfix: Errors in failure backend are rescue'd
32
+ * Bugfix: Non-working workers no longer counted in "working" count
33
+ * Bugfix: Don't think resque-web is a worker
34
+
35
+ ## 1.11.0 (2010-08-23)
36
+
37
+ * Web UI: Group /workers page by hostnames
38
+
39
+ ## 1.10.0 (2010-08-23)
40
+
41
+ * Support redis:// string format in `Resque.redis=`
42
+ * Using new cross-platform JSON gem.
43
+ * Added `after_enqueue` plugin hook.
44
+ * Added `shutdown?` method which can be overridden.
45
+ * Added support for the "leftright" gem when running tests.
46
+ * Grammarfix: In the README
47
+
48
+ ## 1.9.10 (2010-08-06)
49
+
50
+ * Bugfix: before_fork should get passed the job
51
+
52
+ ## 1.9.9 (2010-07-26)
53
+
54
+ * Depend on redis-namespace 0.8.0
55
+ * Depend on json_pure instead of json (for JRuby compat)
56
+ * Bugfix: rails_env display in stats view
57
+
58
+ ## 1.9.8 (2010-07-20)
59
+
60
+ * Bugfix: Worker.all should never return nil
61
+ * monit example: Fixed Syntax Error and adding environment to the rake task
62
+ * redis rake task: Fixed typo in copy command
63
+
64
+ ## 1.9.7 (2010-07-09)
65
+
66
+ * Improved memory usage in Job.destroy
67
+ * redis-namespace 0.7.0 now required
68
+ * Bugfix: Reverted $0 changes
69
+ * Web Bugfix: Payload-less failures in the web ui work
70
+
71
+ ## 1.9.6 (2010-06-22)
72
+
73
+ * Bugfix: Rakefile logging works the same as all the other logging
74
+
75
+ ## 1.9.5 (2010-06-16)
76
+
77
+ * Web Bugfix: Display the configured namespace on the stats page
78
+ * Revert Bugfix: Make ps -o more cross platform friendly
79
+
80
+ ## 1.9.4 (2010-06-14)
81
+
82
+ * Bugfix: Multiple failure backend gets exception information when created
83
+
84
+ ## 1.9.3 (2010-06-14)
85
+
86
+ * Bugfix: Resque#queues always returns an array
87
+
88
+ ## 1.9.2 (2010-06-13)
89
+
90
+ * Bugfix: Worker.all returning nil fix
91
+ * Bugfix: Make ps -o more cross platform friendly
92
+
93
+ ## 1.9.1 (2010-06-04)
94
+
95
+ * Less strict JSON dependency
96
+ * Included HISTORY.md in gem
97
+
98
+ ## 1.9.0 (2010-06-04)
99
+
100
+ * Redis 2 support
101
+ * Depend on redis-namespace 0.5.0
102
+ * Added Resque::VERSION constant (alias of Resque::Version)
103
+ * Bugfix: Specify JSON dependency
104
+ * Bugfix: Hoptoad plugin now works on 1.9
105
+
106
+ ## 1.8.5 (2010-05-18)
107
+
108
+ * Bugfix: Be more liberal in which Redis clients we accept.
109
+
110
+ ## 1.8.4 (2010-05-18)
111
+
112
+ * Try to resolve redis-namespace dependency issue
113
+
114
+ ## 1.8.3 (2010-05-17)
115
+
116
+ * Depend on redis-rb ~> 1.0.7
117
+
118
+ ## 1.8.2 (2010-05-03)
119
+
120
+ * Bugfix: Include "tasks/" dir in RubyGem
121
+
122
+ ## 1.8.1 (2010-04-29)
123
+
124
+ * Bugfix: Multiple failure backend did not support requeue-ing failed jobs
125
+ * Bugfix: Fix /failed when error has no backtrace
126
+ * Bugfix: Add `Redis::DistRedis` as a valid client
127
+
128
+ ## 1.8.0 (2010-04-07)
129
+
130
+ * Jobs that never complete due to killed worker are now failed.
131
+ * Worker "working" state is now maintained by the parent, not the child.
132
+ * Stopped using deprecated redis.rb methods
133
+ * `Worker.working` race condition fixed
134
+ * `Worker#process` has been deprecated.
135
+ * Monit example fixed
136
+ * Redis::Client and Redis::Namespace can be passed to `Resque.redis=`
137
+
138
+ ## 1.7.1 (2010-04-02)
139
+
140
+ * Bugfix: Make job hook execution order consistent
141
+ * Bugfix: stdout buffering in child process
142
+
143
+ ## 1.7.0 (2010-03-31)
144
+
145
+ * Job hooks API. See docs/HOOKS.md.
146
+ * web: Hovering over dates shows a timestamp
147
+ * web: AJAXify retry action for failed jobs
148
+ * web bugfix: Fix pagination bug
149
+
150
+ ## 1.6.1 (2010-03-25)
151
+
152
+ * Bugfix: Workers may not be clearing their state correctly on
153
+ shutdown
154
+ * Added example monit config.
155
+ * Exception class is now recorded when an error is raised in a
156
+ worker.
157
+ * web: Unit tests
158
+ * web: Show namespace in header and footer
159
+ * web: Remove a queue
160
+ * web: Retry failed jobs
161
+
162
+ ## 1.6.0 (2010-03-09)
163
+
164
+ * Added `before_first_fork`, `before_fork`, and `after_fork` hooks.
165
+ * Hoptoad: Added server_environment config setting
166
+ * Hoptoad bugfix: Don't depend on RAILS_ROOT
167
+ * 1.8.6 compat fixes
168
+
169
+ ## 1.5.2 (2010-03-03)
170
+
171
+ * Bugfix: JSON check was crazy.
172
+
173
+ ## 1.5.1 (2010-03-03)
174
+
175
+ * `Job.destroy` and `Resque.dequeue` return the # of destroyed jobs.
176
+ * Hoptoad notifier improvements
177
+ * Specify the namespace with `resque-web` by passing `-N namespace`
178
+ * Bugfix: Don't crash when trying to parse invalid JSON.
179
+ * Bugfix: Non-standard namespace support
180
+ * Web: Red backgound for queue "failed" only shown if there are failed jobs.
181
+ * Web bugfix: Tabs highlight properly now
182
+ * Web bugfix: ZSET partial support in stats
183
+ * Web bugfix: Deleting failed jobs works again
184
+ * Web bugfix: Sets (or zsets, lists, etc) now paginate.
185
+
186
+ ## 1.5.0 (2010-02-17)
187
+
188
+ * Version now included in procline, e.g. `resque-1.5.0: Message`
189
+ * Web bugfix: Ignore idle works in the "working" page
190
+ * Added `Resque::Job.destroy(queue, klass, *args)`
191
+ * Added `Resque.dequeue(klass, *args)`
192
+
193
+ ## 1.4.0 (2010-02-11)
194
+
195
+ * Fallback when unable to bind QUIT and USR1 for Windows and JRuby.
196
+ * Fallback when no `Kernel.fork` is provided (for IronRuby).
197
+ * Web: Rounded corners in Firefox
198
+ * Cut down system calls in `Worker#prune_dead_workers`
199
+ * Enable switching DB in a Redis server from config
200
+ * Support USR2 and CONT to stop and start job processing.
201
+ * Web: Add example failing job
202
+ * Bugfix: `Worker#unregister_worker` shouldn't call `done_working`
203
+ * Bugfix: Example god config now restarts Resque properly.
204
+ * Multiple failure backends now permitted.
205
+ * Hoptoad failure backend updated to new API
206
+
207
+ ## 1.3.1 (2010-01-11)
208
+
209
+ * Vegas bugfix: Don't error without a config
210
+
211
+ ## 1.3.0 (2010-01-11)
212
+
213
+ * Use Vegas for resque-web
214
+ * Web Bugfix: Show proper date/time value for failed_at on Failures
215
+ * Web Bugfix: Make the / route more flexible
216
+ * Add Resque::Server.tabs array (so plugins can add their own tabs)
217
+ * Start using [Semantic Versioning](http://semver.org/)
218
+
219
+ ## 1.2.4 (2009-12-15)
220
+
221
+ * Web Bugfix: fix key links on stat page
222
+
223
+ ## 1.2.3 (2009-12-15)
224
+
225
+ * Bugfix: Fixed `rand` seeding in child processes.
226
+ * Bugfix: Better JSON encoding/decoding without Yajl.
227
+ * Bugfix: Avoid `ps` flag error on Linux
228
+ * Add `PREFIX` observance to `rake` install tasks.
229
+
230
+ ## 1.2.2 (2009-12-08)
231
+
232
+ * Bugfix: Job equality was not properly implemented.
233
+
234
+ ## 1.2.1 (2009-12-07)
235
+
236
+ * Added `rake resque:workers` task for starting multiple workers.
237
+ * 1.9.x compatibility
238
+ * Bugfix: Yajl decoder doesn't care about valid UTF-8
239
+ * config.ru loads RESQUECONFIG if the ENV variable is set.
240
+ * `resque-web` now sets RESQUECONFIG
241
+ * Job objects know if they are equal.
242
+ * Jobs can be re-queued using `Job#recreate`
243
+
244
+ ## 1.2.0 (2009-11-25)
245
+
246
+ * If USR1 is sent and no child is found, shutdown.
247
+ * Raise when a job class does not respond to `perform`.
248
+ * Added `Resque.remove_queue` for deleting a queue
249
+
250
+ ## 1.1.0 (2009-11-04)
251
+
252
+ * Bugfix: Broken ERB tag in failure UI
253
+ * Bugfix: Save the worker's ID, not the worker itself, in the failure module
254
+ * Redesigned the sinatra web interface
255
+ * Added option to clear failed jobs
256
+
257
+ ## 1.0.0 (2009-11-03)
258
+
259
+ * First release.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) Chris Wanstrath
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,828 @@
1
+ Resque-mongo
2
+ ============
3
+ Resque-mongo is a fork of [Resque][resque] that uses MongoDB as a
4
+ backend instead of Redis. This fork is a work in progress, all the
5
+ library functionality has been ported (all tests pass) and the
6
+ monitoring sinatra app works except the "stats" panel, although there are
7
+ a lot of details that need to been taken care of.
8
+
9
+ Resque-mongo uses a fairly new feature of mongo, [findAndModify()][fnr].
10
+ findAndModify that is only supported by 0.20+ version ofthe ruby mongo driver.
11
+
12
+ Also, check your mongo version: 1.3.0 or higher
13
+
14
+ [fnr]: http://www.mongodb.org/display/DOCS/findandmodify+Command
15
+
16
+ gem install nfo-resque-mongo
17
+ # Rails integration, config/environment.rb
18
+ config.gem 'nfo-resque-mongo', :lib => 'resque'
19
+
20
+
21
+ Resque
22
+ ======
23
+
24
+ Resque (pronounced like "rescue") is a Redis-backed library for creating
25
+ background jobs, placing those jobs on multiple queues, and processing
26
+ them later.
27
+
28
+ Background jobs can be any Ruby class or module that responds to
29
+ `perform`. Your existing classes can easily be converted to background
30
+ jobs or you can create new classes specifically to do work. Or, you
31
+ can do both.
32
+
33
+ Resque is heavily inspired by DelayedJob (which rocks) and comprises
34
+ three parts:
35
+
36
+ 1. A Ruby library for creating, querying, and processing jobs
37
+ 2. A Rake task for starting a worker which processes jobs
38
+ 3. A Sinatra app for monitoring queues, jobs, and workers.
39
+
40
+ Resque workers can be distributed between multiple machines,
41
+ support priorities, are resilient to memory bloat / "leaks," are
42
+ optimized for REE (but work on MRI and JRuby), tell you what they're
43
+ doing, and expect failure.
44
+
45
+ Resque queues are persistent; support constant time, atomic push and
46
+ pop (thanks to Redis); provide visibility into their contents; and
47
+ store jobs as simple JSON packages.
48
+
49
+ The Resque frontend tells you what workers are doing, what workers are
50
+ not doing, what queues you're using, what's in those queues, provides
51
+ general usage stats, and helps you track failures.
52
+
53
+
54
+ The Blog Post
55
+ -------------
56
+
57
+ For the backstory, philosophy, and history of Resque's beginnings,
58
+ please see [the blog post][0].
59
+
60
+
61
+ Overview
62
+ --------
63
+
64
+ Resque allows you to create jobs and place them on a queue, then,
65
+ later, pull those jobs off the queue and process them.
66
+
67
+ Resque jobs are Ruby classes (or modules) which respond to the
68
+ `perform` method. Here's an example:
69
+
70
+ class Archive
71
+ @queue = :file_serve
72
+
73
+ def self.perform(repo_id, branch = 'master')
74
+ repo = Repository.find(repo_id)
75
+ repo.create_archive(branch)
76
+ end
77
+ end
78
+
79
+ The `@queue` class instance variable determines which queue `Archive`
80
+ jobs will be placed in. Queues are arbitrary and created on the fly -
81
+ you can name them whatever you want and have as many as you want.
82
+
83
+ To place an `Archive` job on the `file_serve` queue, we might add this
84
+ to our application's pre-existing `Repository` class:
85
+
86
+ class Repository
87
+ def async_create_archive(branch)
88
+ Resque.enqueue(Archive, self.id, branch)
89
+ end
90
+ end
91
+
92
+ Now when we call `repo.async_create_archive('masterbrew')` in our
93
+ application, a job will be created and placed on the `file_serve`
94
+ queue.
95
+
96
+ Later, a worker will run something like this code to process the job:
97
+
98
+ klass, args = Resque.reserve(:file_serve)
99
+ klass.perform(*args) if klass.respond_to? :perform
100
+
101
+ Which translates to:
102
+
103
+ Archive.perform(44, 'masterbrew')
104
+
105
+ Let's start a worker to run `file_serve` jobs:
106
+
107
+ $ cd app_root
108
+ $ QUEUE=file_serve rake resque:work
109
+
110
+ This starts one Resque worker and tells it to work off the
111
+ `file_serve` queue. As soon as it's ready it'll try to run the
112
+ `Resque.reserve` code snippet above and process jobs until it can't
113
+ find any more, at which point it will sleep for a small period and
114
+ repeatedly poll the queue for more jobs.
115
+
116
+ Workers can be given multiple queues (a "queue list") and run on
117
+ multiple machines. In fact they can be run anywhere with network
118
+ access to the Redis server.
119
+
120
+
121
+ Jobs
122
+ ----
123
+
124
+ What should you run in the background? Anything that takes any time at
125
+ all. Slow INSERT statements, disk manipulating, data processing, etc.
126
+
127
+ At GitHub we use Resque to process the following types of jobs:
128
+
129
+ * Warming caches
130
+ * Counting disk usage
131
+ * Building tarballs
132
+ * Building Rubygems
133
+ * Firing off web hooks
134
+ * Creating events in the db and pre-caching them
135
+ * Building graphs
136
+ * Deleting users
137
+ * Updating our search index
138
+
139
+ As of writing we have about 35 different types of background jobs.
140
+
141
+ Keep in mind that you don't need a web app to use Resque - we just
142
+ mention "foreground" and "background" because they make conceptual
143
+ sense. You could easily be spidering sites and sticking data which
144
+ needs to be crunched later into a queue.
145
+
146
+
147
+ ### Persistence
148
+
149
+ Jobs are persisted to queues as JSON objects. Let's take our `Archive`
150
+ example from above. We'll run the following code to create a job:
151
+
152
+ repo = Repository.find(44)
153
+ repo.async_create_archive('masterbrew')
154
+
155
+ The following JSON will be stored in the `file_serve` queue:
156
+
157
+ {
158
+ 'class': 'Archive',
159
+ 'args': [ 44, 'masterbrew' ]
160
+ }
161
+
162
+ Because of this your jobs must only accept arguments that can be JSON encoded.
163
+
164
+ So instead of doing this:
165
+
166
+ Resque.enqueue(Archive, self, branch)
167
+
168
+ do this:
169
+
170
+ Resque.enqueue(Archive, self.id, branch)
171
+
172
+ This is why our above example (and all the examples in `examples/`)
173
+ uses object IDs instead of passing around the objects.
174
+
175
+ While this is less convenient than just sticking a marshaled object
176
+ in the database, it gives you a slight advantage: your jobs will be
177
+ run against the most recent version of an object because they need to
178
+ pull from the DB or cache.
179
+
180
+ If your jobs were run against marshaled objects, they could
181
+ potentially be operating on a stale record with out-of-date information.
182
+
183
+
184
+ ### send_later / async
185
+
186
+ Want something like DelayedJob's `send_later` or the ability to use
187
+ instance methods instead of just methods for jobs? See the `examples/`
188
+ directory for goodies.
189
+
190
+ We plan to provide first class `async` support in a future release.
191
+
192
+
193
+ ### Failure
194
+
195
+ If a job raises an exception, it is logged and handed off to the
196
+ `Resque::Failure` module. Failures are logged either locally in Redis
197
+ or using some different backend.
198
+
199
+ For example, Resque ships with Hoptoad support.
200
+
201
+ Keep this in mind when writing your jobs: you may want to throw
202
+ exceptions you would not normally throw in order to assist debugging.
203
+
204
+
205
+ Workers
206
+ -------
207
+
208
+ Resque workers are rake tasks that run forever. They basically do this:
209
+
210
+ start
211
+ loop do
212
+ if job = reserve
213
+ job.process
214
+ else
215
+ sleep 5
216
+ end
217
+ end
218
+ shutdown
219
+
220
+ Starting a worker is simple. Here's our example from earlier:
221
+
222
+ $ QUEUE=file_serve rake resque:work
223
+
224
+ By default Resque won't know about your application's
225
+ environment. That is, it won't be able to find and run your jobs - it
226
+ needs to load your application into memory.
227
+
228
+ If we've installed Resque as a Rails plugin, we might run this command
229
+ from our RAILS_ROOT:
230
+
231
+ $ QUEUE=file_serve rake environment resque:work
232
+
233
+ This will load the environment before starting a worker. Alternately
234
+ we can define a `resque:setup` task with a dependency on the
235
+ `environment` rake task:
236
+
237
+ task "resque:setup" => :environment
238
+
239
+ GitHub's setup task looks like this:
240
+
241
+ task "resque:setup" => :environment do
242
+ Grit::Git.git_timeout = 10.minutes
243
+ end
244
+
245
+ We don't want the `git_timeout` as high as 10 minutes in our web app,
246
+ but in the Resque workers it's fine.
247
+
248
+
249
+ ### Logging
250
+
251
+ Workers support basic logging to STDOUT. If you start them with the
252
+ `VERBOSE` env variable set, they will print basic debugging
253
+ information. You can also set the `VVERBOSE` (very verbose) env
254
+ variable.
255
+
256
+ $ VVERBOSE=1 QUEUE=file_serve rake environment resque:work
257
+
258
+ ### Process IDs (PIDs)
259
+
260
+ There are scenarios where it's helpful to record the PID of a resque
261
+ worker process. Use the PIDFILE option for easy access to the PID:
262
+
263
+ $ PIDFILE=./resque.pid QUEUE=file_serve rake environment resque:work
264
+
265
+
266
+ ### Priorities and Queue Lists
267
+
268
+ Resque doesn't support numeric priorities but instead uses the order
269
+ of queues you give it. We call this list of queues the "queue list."
270
+
271
+ Let's say we add a `warm_cache` queue in addition to our `file_serve`
272
+ queue. We'd now start a worker like so:
273
+
274
+ $ QUEUES=file_serve,warm_cache rake resque:work
275
+
276
+ When the worker looks for new jobs, it will first check
277
+ `file_serve`. If it finds a job, it'll process it then check
278
+ `file_serve` again. It will keep checking `file_serve` until no more
279
+ jobs are available. At that point, it will check `warm_cache`. If it
280
+ finds a job it'll process it then check `file_serve` (repeating the
281
+ whole process).
282
+
283
+ In this way you can prioritize certain queues. At GitHub we start our
284
+ workers with something like this:
285
+
286
+ $ QUEUES=critical,archive,high,low rake resque:work
287
+
288
+ Notice the `archive` queue - it is specialized and in our future
289
+ architecture will only be run from a single machine.
290
+
291
+ At that point we'll start workers on our generalized background
292
+ machines with this command:
293
+
294
+ $ QUEUES=critical,high,low rake resque:work
295
+
296
+ And workers on our specialized archive machine with this command:
297
+
298
+ $ QUEUE=archive rake resque:work
299
+
300
+
301
+ ### Running All Queues
302
+
303
+ If you want your workers to work off of every queue, including new
304
+ queues created on the fly, you can use a splat:
305
+
306
+ $ QUEUE=* rake resque:work
307
+
308
+ Queues will be processed in alphabetical order.
309
+
310
+
311
+ ### Running Multiple Workers
312
+
313
+ At GitHub we use god to start and stop multiple workers. A sample god
314
+ configuration file is included under `examples/god`. We recommend this
315
+ method.
316
+
317
+ If you'd like to run multiple workers in development mode, you can do
318
+ so using the `resque:workers` rake task:
319
+
320
+ $ COUNT=5 QUEUE=* rake resque:workers
321
+
322
+ This will spawn five Resque workers, each in its own thread. Hitting
323
+ ctrl-c should be sufficient to stop them all.
324
+
325
+
326
+ ### Forking
327
+
328
+ On certain platforms, when a Resque worker reserves a job it
329
+ immediately forks a child process. The child processes the job then
330
+ exits. When the child has exited successfully, the worker reserves
331
+ another job and repeats the process.
332
+
333
+ Why?
334
+
335
+ Because Resque assumes chaos.
336
+
337
+ Resque assumes your background workers will lock up, run too long, or
338
+ have unwanted memory growth.
339
+
340
+ If Resque workers processed jobs themselves, it'd be hard to whip them
341
+ into shape. Let's say one is using too much memory: you send it a
342
+ signal that says "shutdown after you finish processing the current
343
+ job," and it does so. It then starts up again - loading your entire
344
+ application environment. This adds useless CPU cycles and causes a
345
+ delay in queue processing.
346
+
347
+ Plus, what if it's using too much memory and has stopped responding to
348
+ signals?
349
+
350
+ Thanks to Resque's parent / child architecture, jobs that use too much memory
351
+ release that memory upon completion. No unwanted growth.
352
+
353
+ And what if a job is running too long? You'd need to `kill -9` it then
354
+ start the worker again. With Resque's parent / child architecture you
355
+ can tell the parent to forcefully kill the child then immediately
356
+ start processing more jobs. No startup delay or wasted cycles.
357
+
358
+ The parent / child architecture helps us keep tabs on what workers are
359
+ doing, too. By eliminating the need to `kill -9` workers we can have
360
+ parents remove themselves from the global listing of workers. If we
361
+ just ruthlessly killed workers, we'd need a separate watchdog process
362
+ to add and remove them to the global listing - which becomes
363
+ complicated.
364
+
365
+ Workers instead handle their own state.
366
+
367
+
368
+ ### Parents and Children
369
+
370
+ Here's a parent / child pair doing some work:
371
+
372
+ $ ps -e -o pid,command | grep [r]esque
373
+ 92099 resque: Forked 92102 at 1253142769
374
+ 92102 resque: Processing file_serve since 1253142769
375
+
376
+ You can clearly see that process 92099 forked 92102, which has been
377
+ working since 1253142769.
378
+
379
+ (By advertising the time they began processing you can easily use monit
380
+ or god to kill stale workers.)
381
+
382
+ When a parent process is idle, it lets you know what queues it is
383
+ waiting for work on:
384
+
385
+ $ ps -e -o pid,command | grep [r]esque
386
+ 92099 resque: Waiting for file_serve,warm_cache
387
+
388
+
389
+ ### Signals
390
+
391
+ Resque workers respond to a few different signals:
392
+
393
+ * `QUIT` - Wait for child to finish processing then exit
394
+ * `TERM` / `INT` - Immediately kill child then exit
395
+ * `USR1` - Immediately kill child but don't exit
396
+ * `USR2` - Don't start to process any new jobs
397
+ * `CONT` - Start to process new jobs again after a USR2
398
+
399
+ If you want to gracefully shutdown a Resque worker, use `QUIT`.
400
+
401
+ If you want to kill a stale or stuck child, use `USR1`. Processing
402
+ will continue as normal unless the child was not found. In that case
403
+ Resque assumes the parent process is in a bad state and shuts down.
404
+
405
+ If you want to kill a stale or stuck child and shutdown, use `TERM`
406
+
407
+ If you want to stop processing jobs, but want to leave the worker running
408
+ (for example, to temporarily alleviate load), use `USR2` to stop processing,
409
+ then `CONT` to start it again.
410
+
411
+ ### Mysql::Error: MySQL server has gone away
412
+
413
+ If your workers remain idle for too long they may lose their MySQL
414
+ connection. If that happens we recommend using [this
415
+ Gist](http://gist.github.com/238999).
416
+
417
+
418
+ The Front End
419
+ -------------
420
+
421
+ Resque comes with a Sinatra-based front end for seeing what's up with
422
+ your queue.
423
+
424
+ ![The Front End](http://img.skitch.com/20091104-tqh5pgkwgbskjbk7qbtmpesnyw.jpg)
425
+
426
+ ### Standalone
427
+
428
+ If you've installed Resque as a gem running the front end standalone is easy:
429
+
430
+ $ resque-web
431
+
432
+ It's a thin layer around `rackup` so it's configurable as well:
433
+
434
+ $ resque-web -p 8282
435
+
436
+ If you have a Resque config file you want evaluated just pass it to
437
+ the script as the final argument:
438
+
439
+ $ resque-web -p 8282 rails_root/config/initializers/resque.rb
440
+
441
+ You can also set the namespace directly using `resque-web`:
442
+
443
+ $ resque-web -p 8282 -N myapp
444
+
445
+ ### Passenger
446
+
447
+ Using Passenger? Resque ships with a `config.ru` you can use. See
448
+ Phusion's guide:
449
+
450
+ Apache: <http://www.modrails.com/documentation/Users%20guide%20Apache.html#_deploying_a_rack_based_ruby_application>
451
+ Nginx: <http://www.modrails.com/documentation/Users%20guide%20Nginx.html#deploying_a_rack_app>
452
+
453
+ ### Rack::URLMap
454
+
455
+ If you want to load Resque on a subpath, possibly alongside other
456
+ apps, it's easy to do with Rack's `URLMap`:
457
+
458
+ require 'resque/server'
459
+
460
+ run Rack::URLMap.new \
461
+ "/" => Your::App.new,
462
+ "/resque" => Resque::Server.new
463
+
464
+ Check `examples/demo/config.ru` for a functional example (including
465
+ HTTP basic auth).
466
+
467
+
468
+ Resque vs DelayedJob
469
+ --------------------
470
+
471
+ How does Resque compare to DelayedJob, and why would you choose one
472
+ over the other?
473
+
474
+ * Resque supports multiple queues
475
+ * DelayedJob supports finer grained priorities
476
+ * Resque workers are resilient to memory leaks / bloat
477
+ * DelayedJob workers are extremely simple and easy to modify
478
+ * Resque requires Redis
479
+ * DelayedJob requires ActiveRecord
480
+ * Resque can only place JSONable Ruby objects on a queue as arguments
481
+ * DelayedJob can place _any_ Ruby object on its queue as arguments
482
+ * Resque includes a Sinatra app for monitoring what's going on
483
+ * DelayedJob can be queried from within your Rails app if you want to
484
+ add an interface
485
+
486
+ If you're doing Rails development, you already have a database and
487
+ ActiveRecord. DelayedJob is super easy to setup and works great.
488
+ GitHub used it for many months to process almost 200 million jobs.
489
+
490
+ Choose Resque if:
491
+
492
+ * You need multiple queues
493
+ * You don't care / dislike numeric priorities
494
+ * You don't need to persist every Ruby object ever
495
+ * You have potentially huge queues
496
+ * You want to see what's going on
497
+ * You expect a lot of failure / chaos
498
+ * You can setup Redis
499
+ * You're not running short on RAM
500
+
501
+ Choose DelayedJob if:
502
+
503
+ * You like numeric priorities
504
+ * You're not doing a gigantic amount of jobs each day
505
+ * Your queue stays small and nimble
506
+ * There is not a lot failure / chaos
507
+ * You want to easily throw anything on the queue
508
+ * You don't want to setup Redis
509
+
510
+ In no way is Resque a "better" DelayedJob, so make sure you pick the
511
+ tool that's best for your app.
512
+
513
+
514
+ Installing Redis
515
+ ----------------
516
+
517
+ Resque requires Redis 0.900 or higher.
518
+
519
+ Resque uses Redis' lists for its queues. It also stores worker state
520
+ data in Redis.
521
+
522
+ #### Homebrew
523
+
524
+ If you're on OS X, Homebrew is the simplest way to install Redis:
525
+
526
+ $ brew install redis
527
+ $ redis-server /usr/local/etc/redis.conf
528
+
529
+ You now have a Redis daemon running on 6379.
530
+
531
+ #### Via Resque
532
+
533
+ Resque includes Rake tasks (thanks to Ezra's redis-rb) that will
534
+ install and run Redis for you:
535
+
536
+ $ git clone git://github.com/defunkt/resque.git
537
+ $ cd resque
538
+ $ rake redis:install dtach:install
539
+ $ rake redis:start
540
+
541
+ Or, if you don't have admin access on your machine:
542
+
543
+ $ git clone git://github.com/defunkt/resque.git
544
+ $ cd resque
545
+ $ PREFIX=<your_prefix> rake redis:install dtach:install
546
+ $ rake redis:start
547
+
548
+ You now have Redis running on 6379. Wait a second then hit ctrl-\ to
549
+ detach and keep it running in the background.
550
+
551
+ The demo is probably the best way to figure out how to put the parts
552
+ together. But, it's not that hard.
553
+
554
+
555
+ Resque Dependencies
556
+ -------------------
557
+
558
+ gem install redis redis-namespace yajl-ruby vegas sinatra
559
+
560
+ If you cannot install `yajl-ruby` (JRuby?), you can install the `json`
561
+ gem and Resque will use it instead.
562
+
563
+ When problems arise, make sure you have the newest versions of the
564
+ `redis` and `redis-namespace` gems.
565
+
566
+
567
+ Installing Resque
568
+ -----------------
569
+
570
+ ### In a Rack app, as a gem
571
+
572
+ First install the gem.
573
+
574
+ $ gem install resque
575
+
576
+ Next include it in your application.
577
+
578
+ require 'resque'
579
+
580
+ Now start your application:
581
+
582
+ rackup config.ru
583
+
584
+ That's it! You can now create Resque jobs from within your app.
585
+
586
+ To start a worker, create a Rakefile in your app's root (or add this
587
+ to an existing Rakefile):
588
+
589
+ require 'your/app'
590
+ require 'resque/tasks'
591
+
592
+ Now:
593
+
594
+ $ QUEUE=* rake resque:work
595
+
596
+ Alternately you can define a `resque:setup` hook in your Rakefile if you
597
+ don't want to load your app every time rake runs.
598
+
599
+
600
+ ### In a Rails app, as a gem
601
+
602
+ First install the gem.
603
+
604
+ $ gem install resque
605
+
606
+ Next include it in your application.
607
+
608
+ $ cat config/initializers/load_resque.rb
609
+ require 'resque'
610
+
611
+ Now start your application:
612
+
613
+ $ ./script/server
614
+
615
+ That's it! You can now create Resque jobs from within your app.
616
+
617
+ To start a worker, add this to your Rakefile in `RAILS_ROOT`:
618
+
619
+ require 'resque/tasks'
620
+
621
+ Now:
622
+
623
+ $ QUEUE=* rake environment resque:work
624
+
625
+ Don't forget you can define a `resque:setup` hook in
626
+ `lib/tasks/whatever.rake` that loads the `environment` task every time.
627
+
628
+
629
+ ### In a Rails app, as a plugin
630
+
631
+ $ ./script/plugin install git://github.com/defunkt/resque
632
+
633
+ That's it! Resque will automatically be available when your Rails app
634
+ loads.
635
+
636
+ To start a worker:
637
+
638
+ $ QUEUE=* rake environment resque:work
639
+
640
+ Don't forget you can define a `resque:setup` hook in
641
+ `lib/tasks/whatever.rake` that loads the `environment` task every time.
642
+
643
+
644
+ Configuration
645
+ -------------
646
+
647
+ You may want to change the Redis host and port Resque connects to, or
648
+ set various other options at startup.
649
+
650
+ Resque has a `redis` setter which can be given a string or a Redis
651
+ object. This means if you're already using Redis in your app, Resque
652
+ can re-use the existing connection.
653
+
654
+ String: `Resque.redis = 'localhost:6379'`
655
+
656
+ Redis: `Resque.redis = $redis`
657
+
658
+ For our rails app we have a `config/initializers/resque.rb` file where
659
+ we load `config/resque.yml` by hand and set the Redis information
660
+ appropriately.
661
+
662
+ Here's our `config/resque.yml`:
663
+
664
+ development: localhost:6379
665
+ test: localhost:6379
666
+ staging: redis1.se.github.com:6379
667
+ fi: localhost:6379
668
+ production: redis1.ae.github.com:6379
669
+
670
+ And our initializer:
671
+
672
+ rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
673
+ rails_env = ENV['RAILS_ENV'] || 'development'
674
+
675
+ resque_config = YAML.load_file(rails_root + '/config/resque.yml')
676
+ Resque.redis = resque_config[rails_env]
677
+
678
+ Easy peasy! Why not just use `RAILS_ROOT` and `RAILS_ENV`? Because
679
+ this way we can tell our Sinatra app about the config file:
680
+
681
+ $ RAILS_ENV=production resque-web rails_root/config/initializers/resque.rb
682
+
683
+ Now everyone is on the same page.
684
+
685
+ Also, you could disable jobs queueing by setting 'inline' attribute.
686
+ For example, if you want to run all jobs in the same process for cucumber, try:
687
+
688
+ Resque.inline = ENV['RAILS_ENV'] == "cucumber"
689
+
690
+
691
+ Plugins and Hooks
692
+ -----------------
693
+
694
+ For a list of available plugins see
695
+ <http://wiki.github.com/defunkt/resque/plugins>.
696
+
697
+ If you'd like to write your own plugin, or want to customize Resque
698
+ using hooks (such as `Resque.after_fork`), see
699
+ [docs/HOOKS.md](http://github.com/defunkt/resque/blob/master/docs/HOOKS.md).
700
+
701
+
702
+ Namespaces
703
+ ----------
704
+
705
+ If you're running multiple, separate instances of Resque you may want
706
+ to namespace the keyspaces so they do not overlap. This is not unlike
707
+ the approach taken by many memcached clients.
708
+
709
+ This feature is provided by the [redis-namespace][rs] library, which
710
+ Resque uses by default to separate the keys it manages from other keys
711
+ in your Redis server.
712
+
713
+ Simply use the `Resque.redis.namespace` accessor:
714
+
715
+ Resque.redis.namespace = "resque:GitHub"
716
+
717
+ We recommend sticking this in your initializer somewhere after Redis
718
+ is configured.
719
+
720
+
721
+ Demo
722
+ ----
723
+
724
+ Resque ships with a demo Sinatra app for creating jobs that are later
725
+ processed in the background.
726
+
727
+ Try it out by looking at the README, found at `examples/demo/README.markdown`.
728
+
729
+
730
+ Monitoring
731
+ ----------
732
+
733
+ ### god
734
+
735
+ If you're using god to monitor Resque, we have provided example
736
+ configs in `examples/god/`. One is for starting / stopping workers,
737
+ the other is for killing workers that have been running too long.
738
+
739
+ ### monit
740
+
741
+ If you're using monit, `examples/monit/resque.monit` is provided free
742
+ of charge. This is **not** used by GitHub in production, so please
743
+ send patches for any tweaks or improvements you can make to it.
744
+
745
+
746
+ Development
747
+ -----------
748
+
749
+ Want to hack on Resque?
750
+
751
+ First clone the repo and run the tests:
752
+
753
+ git clone git://github.com/defunkt/resque.git
754
+ cd resque
755
+ rake test
756
+
757
+ If the tests do not pass make sure you have Redis installed
758
+ correctly (though we make an effort to tell you if we feel this is the
759
+ case). The tests attempt to start an isolated instance of Redis to
760
+ run against.
761
+
762
+ Also make sure you've installed all the dependencies correctly. For
763
+ example, try loading the `redis-namespace` gem after you've installed
764
+ it:
765
+
766
+ $ irb
767
+ >> require 'rubygems'
768
+ => true
769
+ >> require 'redis/namespace'
770
+ => true
771
+
772
+ If you get an error requiring any of the dependencies, you may have
773
+ failed to install them or be seeing load path issues.
774
+
775
+ Feel free to ping the mailing list with your problem and we'll try to
776
+ sort it out.
777
+
778
+
779
+ Contributing
780
+ ------------
781
+
782
+ Once you've made your great commits:
783
+
784
+ 1. [Fork][1] Resque
785
+ 2. Create a topic branch - `git checkout -b my_branch`
786
+ 3. Push to your branch - `git push origin my_branch`
787
+ 4. Create a [Pull Request](http://help.github.com/pull-requests/) from your branch
788
+ 5. That's it!
789
+
790
+ You might want to checkout our [Contributing][cb] wiki page for information
791
+ on coding standards, new features, etc.
792
+
793
+
794
+ Mailing List
795
+ ------------
796
+
797
+ To join the list simply send an email to <resque@librelist.com>. This
798
+ will subscribe you and send you information about your subscription,
799
+ including unsubscribe information.
800
+
801
+ The archive can be found at <http://librelist.com/browser/resque/>.
802
+
803
+
804
+ Meta
805
+ ----
806
+
807
+ * Code: `git clone git://github.com/defunkt/resque.git`
808
+ * Home: <http://github.com/defunkt/resque>
809
+ * Docs: <http://defunkt.github.com/resque/>
810
+ * Bugs: <http://github.com/defunkt/resque/issues>
811
+ * List: <resque@librelist.com>
812
+ * Chat: <irc://irc.freenode.net/resque>
813
+ * Gems: <http://gemcutter.org/gems/resque>
814
+
815
+ This project uses [Semantic Versioning][sv].
816
+
817
+
818
+ Author
819
+ ------
820
+
821
+ Chris Wanstrath :: chris@ozmm.org :: @defunkt
822
+
823
+ [0]: http://github.com/blog/542-introducing-resque
824
+ [1]: http://help.github.com/forking/
825
+ [2]: http://github.com/defunkt/resque/issues
826
+ [sv]: http://semver.org/
827
+ [rs]: http://github.com/defunkt/redis-namespace
828
+ [cb]: http://wiki.github.com/defunkt/resque/contributing