resque-mongo-scheduler 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .bundle/
2
+ pkg
3
+ nbproject
4
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ resque-mongo-scheduler (2.0.0.a)
5
+ mongo (>= 1.1)
6
+ resque-mongo (>= 1.11.0)
7
+ rufus-scheduler
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ bson (1.1.5)
13
+ json (1.4.6)
14
+ mocha (0.9.10)
15
+ rake
16
+ mongo (1.1.5)
17
+ bson (>= 1.1.5)
18
+ rack (1.2.1)
19
+ rack-test (0.5.6)
20
+ rack (>= 1.0)
21
+ rake (0.8.7)
22
+ resque-mongo (1.11.0)
23
+ json (~> 1.4.6)
24
+ mongo (>= 0.20)
25
+ sinatra (>= 0.9.2)
26
+ vegas (~> 0.1.2)
27
+ rufus-scheduler (2.0.7)
28
+ tzinfo
29
+ sinatra (1.1.0)
30
+ rack (~> 1.1)
31
+ tilt (~> 1.1)
32
+ tilt (1.1)
33
+ tzinfo (0.3.23)
34
+ vegas (0.1.8)
35
+ rack (>= 1.0.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ bundler (>= 1.0.0)
42
+ mocha
43
+ mongo (>= 1.1)
44
+ rack-test
45
+ resque-mongo (>= 1.11.0)
46
+ resque-mongo-scheduler!
47
+ rufus-scheduler
data/HISTORY.md ADDED
@@ -0,0 +1,88 @@
1
+ ## 2.0.0 (???)
2
+
3
+ * Dynamic schedule support (brianjlandau, davidyang)
4
+ * Now depends on redis >=1.3
5
+
6
+ ## 1.9.7 (2010-11-09)
7
+
8
+ * Support for rufus-scheduler "every" syntax (fallwith)
9
+ * Ability to pass a Time to handle_delayed_items for testing/staging (rcarver)
10
+
11
+ ## 1.9.6 (2010-10-08)
12
+
13
+ * Support for custom job classes (like resque-status) (mattetti)
14
+
15
+ ## 1.9.5 (2010-09-09)
16
+
17
+ * Updated scheduler rake task to allow for an alternate setup task
18
+ to avoid loading the entire stack. (chewbranca)
19
+ * Fixed sig issue on win32 (#25)
20
+
21
+ ## 1.9.4 (2010-07-29)
22
+
23
+ * Adding ability to remove jobs from delayed queue (joshsz)
24
+ * Fixing issue #23 (removing .present? reference)
25
+
26
+ ## 1.9.3 (2010-07-07)
27
+
28
+ * Bug fix (#19)
29
+
30
+ ## 1.9.2 (2010-06-16)
31
+
32
+ * Fixing issue with redis gem 2.0.1 and redis server 1.2.6 (dbackeus)
33
+
34
+ ## 1.9.1 (2010-06-04)
35
+
36
+ * Fixing issue with redis server 1.2.6 and redis gem 2.0.1
37
+
38
+ ## 1.9.0 (2010-06-04)
39
+
40
+ * Adding redis 2.0 support (bpo)
41
+
42
+ ## 1.8.2 (2010-06-04)
43
+
44
+ * Adding queue now functionality to delayed timestamps (daviddoan)
45
+
46
+ ## 1.8.1 (2010-05-19)
47
+
48
+ * Adding rails_env for scheduled jobs to support scoping jobs by
49
+ RAILS_ENV (gravis).
50
+ * Fixing ruby 1.8.6 compatibility issue.
51
+ * Adding gemspec for bundler support.
52
+
53
+ ## 1.8.0 (2010-04-14)
54
+
55
+ * Moving version to match corresponding resque version
56
+ * Sorting schedule on Scheduler tab
57
+ * Adding tests for resque-web (gravis)
58
+
59
+ ## 1.0.5 (2010-03-01)
60
+
61
+ * Fixed support for overriding queue from schedule config.
62
+ * Removed resque-web dependency on loading the job classes for "Queue Now",
63
+ provided "queue" is specified in the schedule.
64
+ * The queue is now stored with the job and arguments in the delayed queue so
65
+ there is no longer a need for the scheduler to load job classes to introspect
66
+ the queue.
67
+
68
+ ## 1.0.4 (2010-02-26)
69
+
70
+ * Added support for specifying the queue to put the job onto. This allows for
71
+ you to have one job that can go onto multiple queues and be able to schedule
72
+ jobs without having to load the job classes.
73
+
74
+ ## 1.0.3 (2010-02-11)
75
+
76
+ * Added support for scheduled jobs with empty crons. This is helpful to have
77
+ jobs that you don't want on a schedule, but do want to be able to queue by
78
+ clicking a button.
79
+
80
+ ## 1.0.2 (2010-02-?)
81
+
82
+ * Change Delayed Job tab to display job details if only 1 job exists
83
+ for a given timestamp
84
+
85
+ ## 1.0.1 (2010-01-?)
86
+
87
+ * Bugfix: delayed jobs close together resulted in a 5 second sleep
88
+
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2010 Ben VandenBos
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.
21
+
data/README.markdown ADDED
@@ -0,0 +1,316 @@
1
+ resque-mongo-scheduler
2
+ ======================
3
+
4
+ Resque-mongo-scheduler is a port of [Resque-scheduler](https://github.com/bvandenbos/resque-scheduler)
5
+ that depends on [Resque-mongo](https://github.com/nfo/resque-mongo) instead of [Resque](http://github.com/defunkt/resque).
6
+
7
+ Requires mongo >= 1.6.
8
+
9
+ resque-scheduler
10
+ ===============
11
+
12
+ Resque-scheduler is an extension to [Resque](http://github.com/defunkt/resque)
13
+ that adds support for queueing items in the future.
14
+
15
+ <del>Requires redis >=1.3.</del>
16
+
17
+
18
+ Job scheduling is supported in two different way:
19
+
20
+ ### Recurring (scheduled)
21
+
22
+ Recurring (or scheduled) jobs are logically no different than a standard cron
23
+ job. They are jobs that run based on a fixed schedule which is set at startup.
24
+
25
+ The schedule is a list of Resque worker classes with arguments and a
26
+ schedule frequency (in crontab syntax). The schedule is just a hash, but
27
+ is most likely stored in a YAML like so:
28
+
29
+ queue_documents_for_indexing:
30
+ cron: "0 0 * * *"
31
+ class: QueueDocuments
32
+ args:
33
+ description: "This job queues all content for indexing in solr"
34
+
35
+ clear_leaderboards_contributors:
36
+ cron: "30 6 * * 1"
37
+ class: ClearLeaderboards
38
+ args: contributors
39
+ description: "This job resets the weekly leaderboard for contributions"
40
+
41
+ A queue option can also be specified. Then the job will go onto the specified
42
+ queue if it is available (Even if @queue is specified in the job class). When
43
+ the queue is given it is not necessary for the scheduler to load the class.
44
+
45
+ clear_leaderboards_moderator:
46
+ cron: "30 6 * * 1"
47
+ class: ClearLeaderboards
48
+ queue: scoring
49
+ args: moderators
50
+ description: "This job resets the weekly leaderboard for moderators"
51
+
52
+ And then set the schedule wherever you configure Resque, like so:
53
+
54
+ require 'resque_scheduler'
55
+ Resque.schedule = YAML.load_file(File.join(File.dirname(__FILE__), '../resque_schedule.yml'))
56
+
57
+ Keep in mind, scheduled jobs behave like crons: if your scheduler process (more
58
+ on that later) is not running when a particular job is supposed to be queued,
59
+ it will NOT be ran later when the scheduler process is started back up. In that
60
+ sense, you can sort of think of the scheduler process as crond. Delayed jobs,
61
+ however, are different.
62
+
63
+ A big shout out to [rufus-scheduler](http://github.com/jmettraux/rufus-scheduler)
64
+ for handling the heavy lifting of the actual scheduling engine.
65
+
66
+ ### Delayed jobs
67
+
68
+ Delayed jobs are one-off jobs that you want to be put into a queue at some point
69
+ in the future. The classic example is sending email:
70
+
71
+ Resque.enqueue_at(5.days.from_now, SendFollowUpEmail, :user_id => current_user.id)
72
+
73
+ This will store the job for 5 days in the resque delayed queue at which time the
74
+ scheduler process will pull it from the delayed queue and put it in the
75
+ appropriate work queue for the given job and it will be processed as soon as
76
+ a worker is available.
77
+
78
+ NOTE: The job does not fire **exactly** at the time supplied. Rather, once that
79
+ time is in the past, the job moves from the delayed queue to the actual resque
80
+ work queue and will be completed as workers as free to process it.
81
+
82
+ Also supported is `Resque.enqueue_in` which takes an amount of time in seconds
83
+ in which to queue the job.
84
+
85
+ The delayed queue is stored in redis and is persisted in the same way the
86
+ standard resque jobs are persisted (redis writing to disk). Delayed jobs differ
87
+ from scheduled jobs in that if your scheduler process is down or workers are
88
+ down when a particular job is supposed to be queue, they will simply "catch up"
89
+ once they are started again. Jobs are guaranteed to run (provided they make it
90
+ into the delayed queue) after their given queue_at time has passed.
91
+
92
+ One other thing to note is that insertion into the delayed queue is O(log(n))
93
+ since the jobs are stored in a redis sorted set (zset). I can't imagine this
94
+ being an issue for someone since redis is stupidly fast even at log(n), but full
95
+ disclosure is always best.
96
+
97
+ *Removing Delayed jobs*
98
+
99
+ If you have the need to cancel a delayed job, you can do so thusly:
100
+
101
+ # after you've enqueued a job like:
102
+ Resque.enqueue_at(5.days.from_now, SendFollowUpEmail, :user_id => current_user.id)
103
+ # remove the job with exactly the same parameters:
104
+ Resque.remove_delayed(SendFollowUpEmail, :user_id => current_user.id)
105
+
106
+
107
+ ### Dynamic Schedules
108
+
109
+ If needed you can also have recurring jobs (scheduled) that are dynamically
110
+ defined and updated inside of your application. A good example is if you want
111
+ to allow users to configured when a report is automatically generated. This
112
+ can be completed by loading the schedule initially wherever you configure
113
+ Resque and setting `Resque::Scheduler.dynamic` to `true`. Then subsequently
114
+ updating the "`schedules`" key in redis, namespaced to the Resque namespace.
115
+ The "`schedules`" key is expected to be a redis hash data type, where the key
116
+ is the name of the schedule and the value is a JSON encoded hash of the
117
+ schedule configuration. There are methods on Resque to make this easy (see
118
+ below).
119
+
120
+ When the scheduler loops it will look for differences between the existing
121
+ schedule and the current schedule in redis. If there are differences it will
122
+ make the necessary changes to the running schedule. The schedule names that
123
+ need to be changed are stored in the `schedules_changed` set in redis.
124
+
125
+ To force the scheduler to reload the schedule you just send it the `USR2`
126
+ signal. This will force a complete schedule reload (unscheduling and
127
+ rescheduling everything).
128
+
129
+ To add/update, delete, and retrieve individual schedule items you should
130
+ use the provided API methods:
131
+
132
+ * `Resque.set_schedule(name, config)`
133
+ * `Resque.get_schedule(name)`
134
+ * `Resque.remove_schedule(name)`
135
+
136
+ For example:
137
+
138
+ Resque.set_schedule("create_fake_leaderboards", {
139
+ :cron => "30 6 * * 1",
140
+ :class => "CreateFakeLeaderboards",
141
+ :queue => scoring
142
+ })
143
+
144
+ In this way, it's possible to completely configure your scheduled jobs from
145
+ inside your app if you so desire.
146
+
147
+ ### Support for customized Job classes
148
+
149
+ Some Resque extensions like
150
+ [resque-status](http://github.com/quirkey/resque-status) use custom job
151
+ classes with a slightly different API signature. Resque-scheduler isn't
152
+ trying to support all existing and future custom job classes, instead it
153
+ supports a schedule flag so you can extend your custom class and make it
154
+ support scheduled job.
155
+
156
+ Let's pretend we have a JobWithStatus class called FakeLeaderboard
157
+
158
+ class FakeLeaderboard < Resque::JobWithStatus
159
+ def perform
160
+ # do something and keep track of the status
161
+ end
162
+ end
163
+
164
+ create_fake_leaderboards:
165
+ cron: "30 6 * * 1"
166
+ queue: scoring
167
+ custom_job_class: FakeLeaderboard
168
+ args:
169
+ rails_env: demo
170
+ description: "This job will auto-create leaderboards for our online demo and the status will update as the worker makes progress"
171
+
172
+ If your extension doesn't support scheduled job, you would need to extend the
173
+ custom job class to support the #scheduled method:
174
+
175
+ module Resque
176
+ class JobWithStatus
177
+ # Wrapper API to forward a Resque::Job creation API call into
178
+ # a JobWithStatus call.
179
+ def self.scheduled(queue, klass, *args)
180
+ create(args)
181
+ end
182
+ end
183
+ end
184
+
185
+
186
+ ### Schedule jobs per environment
187
+
188
+ Resque-Scheduler allows to create schedule jobs for specific envs. The arg
189
+ `rails_env` (optional) can be used to determine which envs are concerned by the
190
+ job:
191
+
192
+ create_fake_leaderboards:
193
+ cron: "30 6 * * 1"
194
+ class: CreateFakeLeaderboards
195
+ queue: scoring
196
+ args:
197
+ rails_env: demo
198
+ description: "This job will auto-create leaderboards for our online demo"
199
+
200
+ The scheduled job create_fake_leaderboards will be created only if the
201
+ environment variable `RAILS_ENV` is set to demo:
202
+
203
+ $ RAILS_ENV=demo rake resque:scheduler
204
+
205
+ NOTE: If you have added the 2 lines bellow to your Rails Rakefile
206
+ (ie: lib/tasks/resque-scheduler.rake), the rails env is loaded automatically
207
+ and you don't have to specify RAILS_ENV if the var is correctly set in
208
+ environment.rb
209
+
210
+ Alternatively, you can use your resque initializer to avoid loading the entire
211
+ rails stack.
212
+
213
+ $ rake resque:scheduler INITIALIZER_PATH=config/initializers/resque.rb
214
+
215
+
216
+ Multiple envs are allowed, separated by commas:
217
+
218
+ create_fake_leaderboards:
219
+ cron: "30 6 * * 1"
220
+ class: CreateFakeLeaderboards
221
+ queue: scoring
222
+ args:
223
+ rails_env: demo, staging, production
224
+ description: "This job will auto-create leaderboards"
225
+
226
+ NOTE: If you specify the `rails_env` arg without setting RAILS_ENV as an
227
+ environment variable, the job won't be loaded.
228
+
229
+
230
+ Resque-web additions
231
+ --------------------
232
+
233
+ Resque-scheduler also adds to tabs to the resque-web UI. One is for viewing
234
+ (and manually queueing) the schedule and one is for viewing pending jobs in
235
+ the delayed queue.
236
+
237
+ The Schedule tab:
238
+
239
+ ![The Schedule Tab](http://img.skitch.com/20100111-km2f5gmtpbq23enpujbruj6mgk.png)
240
+
241
+ The Delayed tab:
242
+
243
+ ![The Delayed Tab](http://img.skitch.com/20100111-ne4fcqtc5emkcuwc5qtais2kwx.jpg)
244
+
245
+ Get get these to show up you need to pass a file to `resque-web` to tell it to
246
+ include the `resque-scheduler` plugin. You probably already have a file
247
+ somewhere where you configure `resque`. It probably looks something like this:
248
+
249
+ gem 'resque-mongo'
250
+ require 'resque' # include resque so we can configure it
251
+ Resque.mongo = 'localhost:27017' # tell Resque where MongoDB lives
252
+
253
+ Now, you want to add the following:
254
+
255
+ require 'resque_scheduler' # include the resque_scheduler (this makes the tabs show up)
256
+
257
+ As of resque-scheduler 2.0, it's no longer necessary to have the resque-web
258
+ process aware of the schedule because it reads it from redis. But prior to
259
+ 2.0, you'll want to make sure you load the schedule in this file as well.
260
+ Something like this:
261
+
262
+ Resque.schedule = YAML.load_file(File.join(RAILS_ROOT, 'config/resque_schedule.yml')) # load the schedule
263
+
264
+ Now make sure you're passing that file to resque-web like so:
265
+
266
+ resque-web ~/yourapp/config/resque_config.rb
267
+
268
+ That should make the scheduler tabs show up in `resque-web`.
269
+
270
+
271
+ Installation and the Scheduler process
272
+ --------------------------------------
273
+
274
+ To install:
275
+
276
+ gem install resque-scheduler
277
+
278
+ The unless you specify the `queue` for each scheduled job, the scheduler
279
+ needs to know about your job classes (so it can put them into the appropriate
280
+ queue). To do so, extend the "resque:scheduler_setup" to load your app's code.
281
+ In rails, it would look something like this:
282
+
283
+ require 'resque_scheduler/tasks'
284
+ task "resque:scheduler_setup" => :environment # load the env so we know about the job classes
285
+
286
+ By default, "resque:scheduler_setup" invokes "resque:setup".
287
+
288
+ The scheduler process is just a rake task which is responsible for both queueing
289
+ items from the schedule and polling the delayed queue for items ready to be
290
+ pushed on to the work queues. For obvious reasons, this process never exits.
291
+
292
+ $ rake resque:scheduler
293
+
294
+ Supported environment variables are `VERBOSE` and `MUTE`. If either is set to
295
+ any nonempty value, they will take effect. `VERBOSE` simply dumps more output
296
+ to stdout. `MUTE` does the opposite and silences all output. `MUTE` supersedes
297
+ `VERBOSE`.
298
+
299
+ NOTE: You DO NOT want to run >1 instance of the scheduler. Doing so will result
300
+ in the same job being queued more than once. You only need one instnace of the
301
+ scheduler running per resque instance (regardless of number of machines).
302
+
303
+
304
+ Plagurism alert
305
+ ---------------
306
+
307
+ This was intended to be an extension to resque and so resulted in a lot of the
308
+ code looking very similar to resque, particularly in resque-web and the views. I
309
+ wanted it to be similar enough that someone familiar with resque could easily
310
+ work on resque-scheduler.
311
+
312
+
313
+ Contributing
314
+ ------------
315
+
316
+ For bugs or suggestions, please just open an issue in github.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ $LOAD_PATH.unshift 'lib'
5
+
6
+ task :default => :test
7
+
8
+ desc "Run tests"
9
+ task :test do
10
+ Dir['test/*_test.rb'].each do |f|
11
+ require File.expand_path(f)
12
+ end
13
+ end