clockwork 0.5.4 → 0.5.5
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/README.md +101 -60
- data/Rakefile +2 -2
- data/bin/clockwork +1 -1
- data/clockwork.gemspec +1 -1
- data/example.rb +1 -1
- data/lib/clockwork.rb +8 -10
- data/test/clockwork_test.rb +34 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -16,51 +16,63 @@ Quickstart
|
|
16
16
|
|
17
17
|
Create clock.rb:
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
```ruby
|
20
|
+
require 'clockwork'
|
21
|
+
include Clockwork
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
handler do |job|
|
24
|
+
puts "Running #{job}"
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
every(10.seconds, 'frequent.job')
|
28
|
+
every(3.minutes, 'less.frequent.job')
|
29
|
+
every(1.hour, 'hourly.job')
|
29
30
|
|
30
|
-
|
31
|
+
every(1.day, 'midnight.job', :at => '00:00')
|
32
|
+
```
|
31
33
|
|
32
34
|
Run it with the clockwork binary:
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
```
|
37
|
+
$ clockwork clock.rb
|
38
|
+
Starting clock for 4 events: [ frequent.job less.frequent.job hourly.job midnight.job ]
|
39
|
+
Triggering frequent.job
|
40
|
+
```
|
37
41
|
|
38
42
|
If you would not like to taint the namespace with `include Clockwork`, you can use
|
39
43
|
it as the module (thanks to [hoverlover](https://github.com/hoverlover/clockwork/)).
|
40
44
|
|
41
|
-
|
45
|
+
As reported in [issue #41](https://github.com/tomykaira/clockwork/issues/41#issuecomment-22073609),
|
46
|
+
this technique is necessary when you use Clockwork with Sinatra,
|
47
|
+
because both Sinatra and Clockwork add `register()` method into global namespace.
|
42
48
|
|
43
|
-
|
49
|
+
```ruby
|
50
|
+
require 'clockwork'
|
44
51
|
|
45
|
-
|
46
|
-
config[:tz] = "America/Chicago"
|
47
|
-
end
|
52
|
+
module Clockwork
|
48
53
|
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
configure do |config|
|
55
|
+
config[:tz] = "America/Chicago"
|
56
|
+
end
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
handler do |job|
|
59
|
+
puts "Running #{job}"
|
60
|
+
end
|
56
61
|
|
57
|
-
|
58
|
-
|
62
|
+
every(10.seconds, 'frequent.job')
|
63
|
+
every(3.minutes, 'less.frequent.job')
|
64
|
+
every(1.hour, 'hourly.job')
|
65
|
+
|
66
|
+
every(1.day, 'midnight.job', :at => '00:00')
|
67
|
+
end
|
68
|
+
```
|
59
69
|
|
60
70
|
If you need to load your entire environment for your jobs, simply add:
|
61
71
|
|
62
|
-
|
63
|
-
|
72
|
+
```ruby
|
73
|
+
require './config/boot'
|
74
|
+
require './config/environment'
|
75
|
+
```
|
64
76
|
|
65
77
|
under the `require 'clockwork'` declaration.
|
66
78
|
|
@@ -89,12 +101,14 @@ scalability.
|
|
89
101
|
|
90
102
|
For example, if you're using Beanstalk/Staker:
|
91
103
|
|
92
|
-
|
104
|
+
```ruby
|
105
|
+
require 'stalker'
|
93
106
|
|
94
|
-
|
107
|
+
handler { |job| Stalker.enqueue(job) }
|
95
108
|
|
96
|
-
|
97
|
-
|
109
|
+
every(1.hour, 'feeds.refresh')
|
110
|
+
every(1.day, 'reminders.send', :at => '01:30')
|
111
|
+
```
|
98
112
|
|
99
113
|
Using a queueing system which doesn't require that your full application be
|
100
114
|
loaded is preferable, because the clock process can keep a tiny memory
|
@@ -102,11 +116,13 @@ footprint. If you're using DJ or Resque, however, you can go ahead and load
|
|
102
116
|
your full application enviroment, and use per-event blocks to call DJ or Resque
|
103
117
|
enqueue methods. For example, with DJ/Rails:
|
104
118
|
|
105
|
-
|
106
|
-
|
119
|
+
```ruby
|
120
|
+
require 'config/boot'
|
121
|
+
require 'config/environment'
|
107
122
|
|
108
|
-
|
109
|
-
|
123
|
+
every(1.hour, 'feeds.refresh') { Feed.send_later(:refresh) }
|
124
|
+
every(1.day, 'reminders.send', :at => '01:30') { Reminder.send_later(:send_reminders) }
|
125
|
+
```
|
110
126
|
|
111
127
|
Parameters
|
112
128
|
----------
|
@@ -117,26 +133,36 @@ Parameters
|
|
117
133
|
|
118
134
|
The simplest example:
|
119
135
|
|
120
|
-
|
136
|
+
```ruby
|
137
|
+
every(1.day, 'reminders.send', :at => '01:30')
|
138
|
+
```
|
121
139
|
|
122
140
|
You can omit 0 of the hour:
|
123
141
|
|
124
|
-
|
142
|
+
```ruby
|
143
|
+
every(1.day, 'reminders.send', :at => '1:30')
|
144
|
+
```
|
125
145
|
|
126
146
|
The wildcard for hour is supported:
|
127
147
|
|
128
|
-
|
148
|
+
```ruby
|
149
|
+
every(1.hour, 'reminders.send', :at => '**:30')
|
150
|
+
```
|
129
151
|
|
130
152
|
You can set more than one timing:
|
131
153
|
|
132
|
-
|
133
|
-
|
154
|
+
```ruby
|
155
|
+
every(1.hour, 'reminders.send', :at => ['12:00', '18:00'])
|
156
|
+
# send reminders at noon and evening
|
157
|
+
```
|
134
158
|
|
135
159
|
You can also specify a timezone (default is the local timezone):
|
136
160
|
|
137
|
-
|
138
|
-
|
139
|
-
|
161
|
+
```ruby
|
162
|
+
every(1.day, 'reminders.send', :at => '00:00', :tz => 'UTC')
|
163
|
+
# Runs the job each day at midnight, UTC.
|
164
|
+
# The value for :tz can be anything supported by [TZInfo](http://tzinfo.rubyforge.org/)
|
165
|
+
```
|
140
166
|
|
141
167
|
### :if
|
142
168
|
|
@@ -145,14 +171,17 @@ return value is true.
|
|
145
171
|
|
146
172
|
Run on every first day of month.
|
147
173
|
|
148
|
-
|
174
|
+
```ruby
|
175
|
+
Clockwork.every(1.day, 'myjob', :if => lambda { |t| t.day == 1 })
|
176
|
+
```
|
149
177
|
|
150
178
|
The argument is an instance of `ActiveSupport::TimeWithZone` if the `:tz` option is set. Otherwise, it's an instance of `Time`.
|
151
179
|
|
152
180
|
This argument cannot be omitted. Please use _ as placeholder if not needed.
|
153
181
|
|
154
|
-
|
155
|
-
|
182
|
+
```ruby
|
183
|
+
Clockwork.every(1.second, 'myjob', :if => lambda { |_| true })
|
184
|
+
```
|
156
185
|
|
157
186
|
### :thread
|
158
187
|
|
@@ -188,12 +217,14 @@ jobs.
|
|
188
217
|
|
189
218
|
### Configuration example
|
190
219
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
220
|
+
```ruby
|
221
|
+
Clockwork.configure do |config|
|
222
|
+
config[:sleep_timeout] = 5
|
223
|
+
config[:logger] = Logger.new(log_file_path)
|
224
|
+
config[:tz] = 'EST'
|
225
|
+
config[:max_threads] = 15
|
226
|
+
end
|
227
|
+
```
|
197
228
|
|
198
229
|
Anatomy of a clock file
|
199
230
|
-----------------------
|
@@ -205,7 +236,9 @@ and then the events themselves.
|
|
205
236
|
|
206
237
|
The handler typically looks like this:
|
207
238
|
|
208
|
-
|
239
|
+
```ruby
|
240
|
+
handler { |job| enqueue_your_job(job) }
|
241
|
+
```
|
209
242
|
|
210
243
|
This block will be invoked every time an event is triggered, with the job name
|
211
244
|
passed in. In most cases, you should be able to pass the job name directly
|
@@ -213,8 +246,10 @@ through to your queueing system.
|
|
213
246
|
|
214
247
|
The second part of the file are the events, which roughly resembles a crontab:
|
215
248
|
|
216
|
-
|
217
|
-
|
249
|
+
```ruby
|
250
|
+
every(5.minutes, 'thing.do')
|
251
|
+
every(1.hour, 'otherthing.do')
|
252
|
+
```
|
218
253
|
|
219
254
|
In the first line of this example, an event will be triggered once every five
|
220
255
|
minutes, passing the job name 'thing.do' into the handler. The handler shown
|
@@ -225,16 +260,20 @@ rely on classes rather than job names (i.e. DJ and Resque). In this case, you
|
|
225
260
|
need not define a general event handler, and instead provide one with each
|
226
261
|
event:
|
227
262
|
|
228
|
-
|
263
|
+
```ruby
|
264
|
+
every(5.minutes, 'thing.do') { Thing.send_later(:do) }
|
265
|
+
```
|
229
266
|
|
230
267
|
If you provide a custom handler for the block, the job name is used only for
|
231
268
|
logging.
|
232
269
|
|
233
270
|
You can also use blocks to do more complex checks:
|
234
271
|
|
235
|
-
|
236
|
-
|
237
|
-
|
272
|
+
```ruby
|
273
|
+
every(1.day, 'check.leap.year') do
|
274
|
+
Stalker.enqueue('leap.year.party') if Time.now.year % 4 == 0
|
275
|
+
end
|
276
|
+
```
|
238
277
|
|
239
278
|
In production
|
240
279
|
-------------
|
@@ -259,7 +298,9 @@ You need `daemons` gem to use `clockworkd`. It is not automatically installed,
|
|
259
298
|
|
260
299
|
Then,
|
261
300
|
|
262
|
-
|
301
|
+
```
|
302
|
+
clockworkd -c YOUR_CLOCK.rb start
|
303
|
+
```
|
263
304
|
|
264
305
|
For more details, see help shown by `clockworkd`.
|
265
306
|
|
data/Rakefile
CHANGED
data/bin/clockwork
CHANGED
data/clockwork.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "clockwork"
|
3
|
-
s.version = "0.5.
|
3
|
+
s.version = "0.5.5"
|
4
4
|
|
5
5
|
s.authors = ["Adam Wiggins", "tomykaira"]
|
6
6
|
s.description = "A scheduler process to replace cron, using a more flexible Ruby syntax running as a single long-running process. Inspired by rufus-scheduler and resque-scheduler."
|
data/example.rb
CHANGED
data/lib/clockwork.rb
CHANGED
@@ -17,7 +17,7 @@ module Clockwork
|
|
17
17
|
case at
|
18
18
|
when /^([[:alpha:]]+)\s(.*)$/
|
19
19
|
ret = parse($2)
|
20
|
-
wday = WDAYS.find_index {|x| x.include?($1) }
|
20
|
+
wday = WDAYS.find_index { |x| x.include?($1) }
|
21
21
|
raise FailedToParse, at if wday.nil?
|
22
22
|
ret.wday = wday
|
23
23
|
ret
|
@@ -69,9 +69,7 @@ module Clockwork
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
@thread = options[:thread]
|
74
|
-
end
|
72
|
+
@thread = !!(options.has_key?(:thread) ? options[:thread] : Clockwork.config[:thread])
|
75
73
|
|
76
74
|
@timezone = options[:tz] || Clockwork.config[:tz]
|
77
75
|
end
|
@@ -94,16 +92,12 @@ module Clockwork
|
|
94
92
|
@thread
|
95
93
|
end
|
96
94
|
|
97
|
-
def thread_available?
|
98
|
-
Thread.list.count < Clockwork.config[:max_threads]
|
99
|
-
end
|
100
|
-
|
101
95
|
def run(t)
|
102
96
|
t = convert_timezone(t)
|
103
97
|
@last = t
|
104
98
|
|
105
99
|
if thread?
|
106
|
-
if thread_available?
|
100
|
+
if Clockwork.thread_available?
|
107
101
|
Thread.new { execute }
|
108
102
|
else
|
109
103
|
log_error "Threads exhausted; skipping #{self}"
|
@@ -135,6 +129,10 @@ module Clockwork
|
|
135
129
|
end
|
136
130
|
end
|
137
131
|
|
132
|
+
def thread_available?
|
133
|
+
Thread.list.count < config[:max_threads]
|
134
|
+
end
|
135
|
+
|
138
136
|
def configure
|
139
137
|
yield(config)
|
140
138
|
end
|
@@ -146,7 +144,7 @@ module Clockwork
|
|
146
144
|
extend self
|
147
145
|
|
148
146
|
def default_configuration
|
149
|
-
{ :sleep_timeout => 1, :logger => Logger.new(STDOUT), :max_threads => 10 }
|
147
|
+
{ :sleep_timeout => 1, :logger => Logger.new(STDOUT), :thread => false, :max_threads => 10 }
|
150
148
|
end
|
151
149
|
|
152
150
|
@@configuration = default_configuration
|
data/test/clockwork_test.rb
CHANGED
@@ -180,17 +180,20 @@ class ClockworkTest < Test::Unit::TestCase
|
|
180
180
|
config[:sleep_timeout] = 200
|
181
181
|
config[:logger] = "A Logger"
|
182
182
|
config[:max_threads] = 10
|
183
|
+
config[:thread] = true
|
183
184
|
end
|
184
185
|
|
185
186
|
assert_equal 200, Clockwork.config[:sleep_timeout]
|
186
187
|
assert_equal "A Logger", Clockwork.config[:logger]
|
187
188
|
assert_equal 10, Clockwork.config[:max_threads]
|
189
|
+
assert_equal true, Clockwork.config[:thread]
|
188
190
|
end
|
189
191
|
|
190
192
|
test "configuration should have reasonable defaults" do
|
191
193
|
assert_equal 1, Clockwork.config[:sleep_timeout]
|
192
194
|
assert Clockwork.config[:logger].is_a?(Logger)
|
193
195
|
assert_equal 10, Clockwork.config[:max_threads]
|
196
|
+
assert_equal false, Clockwork.config[:thread]
|
194
197
|
end
|
195
198
|
|
196
199
|
test "should be able to specify a different timezone than local" do
|
@@ -246,7 +249,7 @@ class ClockworkTest < Test::Unit::TestCase
|
|
246
249
|
end
|
247
250
|
|
248
251
|
test ":if it is compared to a time with zone" do
|
249
|
-
tz =
|
252
|
+
tz = 'America/Chicago'
|
250
253
|
time = Time.utc(2012,5,25,10,00)
|
251
254
|
Clockwork.every(1.second, 'myjob', tz: tz, :if => lambda { |t|(
|
252
255
|
((time - 1.hour)..(time + 1.hour)).cover? t
|
@@ -271,4 +274,34 @@ class ClockworkTest < Test::Unit::TestCase
|
|
271
274
|
Clockwork.tick(Time.now)
|
272
275
|
end
|
273
276
|
|
277
|
+
describe "thread option" do
|
278
|
+
test "should not use thread by default" do
|
279
|
+
event = Clockwork.every(1.minute, 'myjob')
|
280
|
+
assert !event.thread?
|
281
|
+
end
|
282
|
+
|
283
|
+
test "should use thread if thread option is specified with truly value" do
|
284
|
+
event = Clockwork.every(1.minute, 'myjob', :thread => true)
|
285
|
+
assert event.thread?
|
286
|
+
end
|
287
|
+
|
288
|
+
test "should use thread if global thread option is set" do
|
289
|
+
Clockwork.configure do |config|
|
290
|
+
config[:thread] = true
|
291
|
+
end
|
292
|
+
|
293
|
+
event = Clockwork.every(1.minute, 'myjob')
|
294
|
+
assert event.thread?
|
295
|
+
end
|
296
|
+
|
297
|
+
test "should not use thread if job option overrides global option" do
|
298
|
+
Clockwork.configure do |config|
|
299
|
+
config[:thread] = true
|
300
|
+
end
|
301
|
+
|
302
|
+
event = Clockwork.every(1.minute, 'myjob', :thread => false)
|
303
|
+
assert !event.thread?
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
274
307
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clockwork
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-08-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: tzinfo
|
@@ -163,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
163
|
version: '0'
|
164
164
|
segments:
|
165
165
|
- 0
|
166
|
-
hash:
|
166
|
+
hash: -871026735
|
167
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
168
|
none: false
|
169
169
|
requirements:
|
@@ -172,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
172
|
version: '0'
|
173
173
|
segments:
|
174
174
|
- 0
|
175
|
-
hash:
|
175
|
+
hash: -871026735
|
176
176
|
requirements: []
|
177
177
|
rubyforge_project:
|
178
178
|
rubygems_version: 1.8.23
|