rufus-scheduler 3.0.8 → 3.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +6 -0
- data/CREDITS.txt +2 -0
- data/README.md +67 -0
- data/lib/rufus/scheduler.rb +58 -59
- data/lib/rufus/scheduler/jobs.rb +14 -13
- data/lib/rufus/scheduler/locks.rb +95 -0
- data/lib/rufus/scheduler/util.rb +1 -1
- data/spec/basics_spec.rb +16 -11
- data/spec/{custom_locks_spec.rb → lock_custom_spec.rb} +0 -0
- data/spec/lock_flock_spec.rb +47 -0
- data/spec/{lockfile_spec.rb → lock_lockfile_spec.rb} +0 -0
- data/spec/lock_spec.rb +59 -0
- data/spec/parse_spec.rb +4 -0
- data/spec/scheduler_spec.rb +1 -1
- metadata +8 -5
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== rufus-scheduler - 3.0.9 released 2014/08/30
|
6
|
+
|
7
|
+
- fix TZ with underscores, thanks https://github.com/gnilrets
|
8
|
+
- integrate https://github.com/ecin Lock mecha
|
9
|
+
|
10
|
+
|
5
11
|
== rufus-scheduler - 3.0.8 released 2014/06/09
|
6
12
|
|
7
13
|
- handle TZInfo errors on DST transitions, thanks https://github.com/junhanamaki
|
data/CREDITS.txt
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
== Contributors
|
6
6
|
|
7
|
+
- Sterling Paramore (https://github.com/gnilrets) underscore TZ fix
|
8
|
+
- ecin (https://github.com/ecin) new lock mecha
|
7
9
|
- Adam Jonas (https://github.com/adamjonas) migrate specs to "expect"
|
8
10
|
- Yassen Bantchev (https://github.com/yassenb) CronLine#previous_time rewrite
|
9
11
|
- Eric Lindvall (https://github.com/eric) Zookeeper locked example
|
data/README.md
CHANGED
@@ -89,6 +89,8 @@ There is no EventMachine-based scheduler anymore.
|
|
89
89
|
|
90
90
|
So you need help. People can help you, but first help them help you, and don't waste their time. Provide a complete description of the issue. If it works on A but not on B and others have to ask you: "so what is different between A and B" you are wasting everyone's time.
|
91
91
|
|
92
|
+
"hello" and "thanks" are not swear words.
|
93
|
+
|
92
94
|
Go read [how to report bugs effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html), twice.
|
93
95
|
|
94
96
|
Update: [help_help.md](https://gist.github.com/jmettraux/310fed75f568fd731814) might help help you.
|
@@ -1097,6 +1099,57 @@ This is useful in environments where the Ruby process holding the scheduler gets
|
|
1097
1099
|
|
1098
1100
|
If the lockfile mechanism here is not sufficient, you can plug your custom mechanism. It's explained in [advanced lock schemes](#advanced-lock-schemes) below.
|
1099
1101
|
|
1102
|
+
### :scheduler_lock
|
1103
|
+
|
1104
|
+
(since rufus-scheduler 3.0.9)
|
1105
|
+
|
1106
|
+
The scheduler lock is an object that responds to `#lock` and `#unlock`. The scheduler calls `#lock` when starting up. If the answer is `false`, the scheduler stops its initialization work and won't schedule anything.
|
1107
|
+
|
1108
|
+
Here is a sample of a scheduler lock that only lets the scheduler on host "coffee.example.com" start:
|
1109
|
+
```ruby
|
1110
|
+
class HostLock
|
1111
|
+
def initialize(lock_name)
|
1112
|
+
@lock_name = lock_name
|
1113
|
+
end
|
1114
|
+
def lock
|
1115
|
+
@lock_name == `hostname -f`.strip
|
1116
|
+
end
|
1117
|
+
def unlock
|
1118
|
+
true
|
1119
|
+
end
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
scheduler =
|
1123
|
+
Rufus::Scheduler.new(:scheduler_lock => HostLock.new('coffee.example.com'))
|
1124
|
+
```
|
1125
|
+
|
1126
|
+
By default, the scheduler_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that returns true.
|
1127
|
+
|
1128
|
+
### :trigger_lock
|
1129
|
+
|
1130
|
+
(since rufus-scheduler 3.0.9)
|
1131
|
+
|
1132
|
+
The trigger lock in an object that responds to `#lock`. The scheduler calls that method on the job lock right before triggering any job. If the answer is false, the trigger doesn't happen, the job is not done (at least not in this scheduler).
|
1133
|
+
|
1134
|
+
Here is a (stupid) PingLock example, it'll only trigger if an "other host" is not responding to ping. Do not use that in production, you don't want to fork a ping process for each trigger attempt...
|
1135
|
+
```ruby
|
1136
|
+
class PingLock
|
1137
|
+
def initialize(other_host)
|
1138
|
+
@other_host = other_host
|
1139
|
+
end
|
1140
|
+
def lock
|
1141
|
+
! system("ping -c 1 #{@other_host}")
|
1142
|
+
end
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
scheduler =
|
1146
|
+
Rufus::Scheduler.new(:trigger_lock => PingLock.new('main.example.com'))
|
1147
|
+
```
|
1148
|
+
|
1149
|
+
By default, the trigger_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that always returns true.
|
1150
|
+
|
1151
|
+
As explained in [advanced lock schemes](#advanced-lock-schemes), another way to tune that behaviour is by overriding the scheduler's `#confirm_lock` method. (You could also do that with an `#on_pre_trigger` callback).
|
1152
|
+
|
1100
1153
|
### :max_work_threads
|
1101
1154
|
|
1102
1155
|
In rufus-scheduler 2.x, by default, each job triggering received its own, brand new, thread of execution. In rufus-scheduler 3.x, execution happens in a pooled work thread. The max work thread count (the pool size) defaults to 28.
|
@@ -1183,6 +1236,20 @@ to make sure that the lock is still valid.
|
|
1183
1236
|
|
1184
1237
|
The #confirm_lock method is called right before a job triggers (if it is provided). The more generic callback #on_pre_trigger is called right after #confirm_lock.
|
1185
1238
|
|
1239
|
+
### :scheduler_lock and :trigger_lock
|
1240
|
+
|
1241
|
+
(introduced in rufus-scheduler 3.0.9).
|
1242
|
+
|
1243
|
+
Another way of prodiving `#lock`, `#unlock` and `#confirm_lock` to a rufus-scheduler is by using the `:scheduler_lock` and `:trigger_lock` options.
|
1244
|
+
|
1245
|
+
See [:trigger_lock](#trigger_lock) and [:scheduler_lock](#scheduler_lock).
|
1246
|
+
|
1247
|
+
The scheduler lock may be used to prevent a scheduler from starting, while a trigger lock prevents individual jobs from triggering (the scheduler goes on scheduling).
|
1248
|
+
|
1249
|
+
One has to be careful with what goes in `#confirm_lock` or in a trigger lock, as it gets called before each trigger.
|
1250
|
+
|
1251
|
+
Warning: you may think you're heading towards "high availability" by using a trigger lock and having lots of schedulers at hand. It may be so if you limit yourself to scheduling the same set of jobs at scheduler startup. But if you add schedules at runtime, they stay local to their scheduler. There is no magic that propagates the jobs to all the schedulers in your pack.
|
1252
|
+
|
1186
1253
|
|
1187
1254
|
## parsing cronlines and time strings
|
1188
1255
|
|
data/lib/rufus/scheduler.rb
CHANGED
@@ -26,7 +26,6 @@ require 'date' if RUBY_VERSION < '1.9.0'
|
|
26
26
|
require 'time'
|
27
27
|
require 'thread'
|
28
28
|
require 'tzinfo'
|
29
|
-
require 'fileutils'
|
30
29
|
|
31
30
|
|
32
31
|
module Rufus
|
@@ -37,8 +36,9 @@ module Rufus
|
|
37
36
|
require 'rufus/scheduler/jobs'
|
38
37
|
require 'rufus/scheduler/cronline'
|
39
38
|
require 'rufus/scheduler/job_array'
|
39
|
+
require 'rufus/scheduler/locks'
|
40
40
|
|
41
|
-
VERSION = '3.0.
|
41
|
+
VERSION = '3.0.9'
|
42
42
|
|
43
43
|
#
|
44
44
|
# A common error class for rufus-scheduler
|
@@ -93,7 +93,17 @@ module Rufus
|
|
93
93
|
|
94
94
|
@thread_key = "rufus_scheduler_#{self.object_id}"
|
95
95
|
|
96
|
-
|
96
|
+
@scheduler_lock =
|
97
|
+
if lockfile = opts[:lockfile]
|
98
|
+
Rufus::Scheduler::FileLock.new(lockfile)
|
99
|
+
else
|
100
|
+
opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new
|
101
|
+
end
|
102
|
+
|
103
|
+
@trigger_lock = opts[:trigger_lock] || Rufus::Scheduler::NullLock.new
|
104
|
+
|
105
|
+
# If we can't grab the @scheduler_lock, don't run.
|
106
|
+
@scheduler_lock.lock || return
|
97
107
|
|
98
108
|
start
|
99
109
|
end
|
@@ -324,6 +334,49 @@ module Rufus
|
|
324
334
|
@jobs[job_id]
|
325
335
|
end
|
326
336
|
|
337
|
+
# Returns true if the scheduler has acquired the [exclusive] lock and
|
338
|
+
# thus may run.
|
339
|
+
#
|
340
|
+
# Most of the time, a scheduler is run alone and this method should
|
341
|
+
# return true. It is useful in cases where among a group of applications
|
342
|
+
# only one of them should run the scheduler. For schedulers that should
|
343
|
+
# not run, the method should return false.
|
344
|
+
#
|
345
|
+
# Out of the box, rufus-scheduler proposes the
|
346
|
+
# :lockfile => 'path/to/lock/file' scheduler start option. It makes
|
347
|
+
# it easy for schedulers on the same machine to determine which should
|
348
|
+
# run (the first to write the lockfile and lock it). It uses "man 2 flock"
|
349
|
+
# so it probably won't work reliably on distributed file systems.
|
350
|
+
#
|
351
|
+
# If one needs to use a special/different locking mechanism, the scheduler
|
352
|
+
# accepts :scheduler_lock => lock_object. lock_object only needs to respond
|
353
|
+
# to #lock
|
354
|
+
# and #unlock, and both of these methods should be idempotent.
|
355
|
+
#
|
356
|
+
# Look at rufus/scheduler/locks.rb for an example.
|
357
|
+
#
|
358
|
+
def lock
|
359
|
+
|
360
|
+
@scheduler_lock.lock
|
361
|
+
end
|
362
|
+
|
363
|
+
# Sister method to #lock, is called when the scheduler shuts down.
|
364
|
+
#
|
365
|
+
def unlock
|
366
|
+
|
367
|
+
@trigger_lock.unlock
|
368
|
+
@scheduler_lock.unlock
|
369
|
+
end
|
370
|
+
|
371
|
+
# Callback called when a job is triggered. If the lock cannot be acquired,
|
372
|
+
# the job won't run (though it'll still be scheduled to run again if
|
373
|
+
# necessary).
|
374
|
+
#
|
375
|
+
def confirm_lock
|
376
|
+
|
377
|
+
@trigger_lock.lock
|
378
|
+
end
|
379
|
+
|
327
380
|
# Returns true if this job is currently scheduled.
|
328
381
|
#
|
329
382
|
# Takes extra care to answer true if the job is a repeat job
|
@@ -423,7 +476,8 @@ module Rufus
|
|
423
476
|
stderr.puts(" #{pre} opts:")
|
424
477
|
stderr.puts(" #{pre} #{@opts.inspect}")
|
425
478
|
stderr.puts(" #{pre} frequency: #{self.frequency}")
|
426
|
-
stderr.puts(" #{pre}
|
479
|
+
stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}")
|
480
|
+
stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}")
|
427
481
|
stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})")
|
428
482
|
stderr.puts(" #{pre} down?: #{down?}")
|
429
483
|
stderr.puts(" #{pre} threads: #{self.threads.size}")
|
@@ -468,61 +522,6 @@ module Rufus
|
|
468
522
|
end
|
469
523
|
end
|
470
524
|
|
471
|
-
# Returns true if the scheduler has acquired the [exclusive] lock and
|
472
|
-
# thus may run.
|
473
|
-
#
|
474
|
-
# Most of the time, a scheduler is run alone and this method should
|
475
|
-
# return true. It is useful in cases where among a group of applications
|
476
|
-
# only one of them should run the scheduler. For schedulers that should
|
477
|
-
# not run, the method should return false.
|
478
|
-
#
|
479
|
-
# Out of the box, rufus-scheduler proposes the
|
480
|
-
# :lockfile => 'path/to/lock/file' scheduler start option. It makes
|
481
|
-
# it easy for schedulers on the same machine to determine which should
|
482
|
-
# run (to first to write the lockfile and lock it). It uses "man 2 flock"
|
483
|
-
# so it probably won't work reliably on distributed file systems.
|
484
|
-
#
|
485
|
-
# If one needs to use a special/different locking mechanism, providing
|
486
|
-
# overriding implementation for this #lock and the #unlock complement is
|
487
|
-
# easy.
|
488
|
-
#
|
489
|
-
def lock
|
490
|
-
|
491
|
-
@lockfile = nil
|
492
|
-
|
493
|
-
return true unless f = @opts[:lockfile]
|
494
|
-
|
495
|
-
raise ArgumentError.new(
|
496
|
-
":lockfile argument must be a string, not a #{f.class}"
|
497
|
-
) unless f.is_a?(String)
|
498
|
-
|
499
|
-
FileUtils.mkdir_p(File.dirname(f))
|
500
|
-
|
501
|
-
f = File.new(f, File::RDWR | File::CREAT)
|
502
|
-
locked = f.flock(File::LOCK_NB | File::LOCK_EX)
|
503
|
-
|
504
|
-
return false unless locked
|
505
|
-
|
506
|
-
now = Time.now
|
507
|
-
|
508
|
-
f.print("pid: #{$$}, ")
|
509
|
-
f.print("scheduler.object_id: #{self.object_id}, ")
|
510
|
-
f.print("time: #{now}, ")
|
511
|
-
f.print("timestamp: #{now.to_f}")
|
512
|
-
f.flush
|
513
|
-
|
514
|
-
@lockfile = f
|
515
|
-
|
516
|
-
true
|
517
|
-
end
|
518
|
-
|
519
|
-
# Sister method to #lock, is called when the scheduler shuts down.
|
520
|
-
#
|
521
|
-
def unlock
|
522
|
-
|
523
|
-
@lockfile.flock(File::LOCK_UN) if @lockfile
|
524
|
-
end
|
525
|
-
|
526
525
|
def terminate_all_jobs
|
527
526
|
|
528
527
|
jobs.each { |j| j.unschedule }
|
data/lib/rufus/scheduler/jobs.rb
CHANGED
@@ -117,15 +117,16 @@ module Rufus
|
|
117
117
|
|
118
118
|
def trigger(time)
|
119
119
|
|
120
|
-
set_next_time(
|
120
|
+
set_next_time(time)
|
121
121
|
|
122
|
-
return if
|
123
|
-
|
124
|
-
|
122
|
+
return if (
|
123
|
+
opts[:overlap] == false &&
|
124
|
+
running?
|
125
|
+
)
|
126
|
+
return if (
|
125
127
|
callback(:confirm_lock, time) &&
|
126
128
|
callback(:on_pre_trigger, time)
|
127
|
-
|
128
|
-
return if r == false
|
129
|
+
) == false
|
129
130
|
|
130
131
|
@count += 1
|
131
132
|
|
@@ -272,7 +273,7 @@ module Rufus
|
|
272
273
|
|
273
274
|
def post_trigger(time)
|
274
275
|
|
275
|
-
set_next_time(
|
276
|
+
set_next_time(time, true)
|
276
277
|
|
277
278
|
callback(:on_post_trigger, time)
|
278
279
|
end
|
@@ -356,7 +357,7 @@ module Rufus
|
|
356
357
|
|
357
358
|
# There is no next_time for one time jobs, hence the false.
|
358
359
|
#
|
359
|
-
def set_next_time(
|
360
|
+
def set_next_time(trigger_time, is_post=false)
|
360
361
|
|
361
362
|
@next_time = is_post ? nil : false
|
362
363
|
end
|
@@ -527,12 +528,12 @@ module Rufus
|
|
527
528
|
"of #{@frequency.inspect} (#{@original.inspect})"
|
528
529
|
) if @frequency <= 0
|
529
530
|
|
530
|
-
set_next_time(
|
531
|
+
set_next_time(nil)
|
531
532
|
end
|
532
533
|
|
533
534
|
protected
|
534
535
|
|
535
|
-
def set_next_time(
|
536
|
+
def set_next_time(trigger_time, is_post=false)
|
536
537
|
|
537
538
|
return if is_post
|
538
539
|
|
@@ -567,12 +568,12 @@ module Rufus
|
|
567
568
|
"of #{@interval.inspect} (#{@original.inspect})"
|
568
569
|
) if @interval <= 0
|
569
570
|
|
570
|
-
set_next_time(
|
571
|
+
set_next_time(nil)
|
571
572
|
end
|
572
573
|
|
573
574
|
protected
|
574
575
|
|
575
|
-
def set_next_time(
|
576
|
+
def set_next_time(trigger_time, is_post=false)
|
576
577
|
|
577
578
|
@next_time =
|
578
579
|
if is_post
|
@@ -616,7 +617,7 @@ module Rufus
|
|
616
617
|
|
617
618
|
protected
|
618
619
|
|
619
|
-
def set_next_time(
|
620
|
+
def set_next_time(trigger_time, is_post=false)
|
620
621
|
|
621
622
|
@next_time = @cron_line.next_time
|
622
623
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006-2014, John Mettraux, jmettraux@gmail.com
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
# Made in Japan.
|
23
|
+
#++
|
24
|
+
|
25
|
+
require 'fileutils'
|
26
|
+
|
27
|
+
|
28
|
+
class Rufus::Scheduler
|
29
|
+
|
30
|
+
#
|
31
|
+
# A lock that can always be acquired
|
32
|
+
#
|
33
|
+
class NullLock
|
34
|
+
|
35
|
+
# Locking is always successful.
|
36
|
+
#
|
37
|
+
def lock; true; end
|
38
|
+
|
39
|
+
def locked?; true; end
|
40
|
+
def unlock; true; end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# The standard flock mecha, with its own class thanks to @ecin
|
45
|
+
#
|
46
|
+
class FileLock
|
47
|
+
|
48
|
+
attr_reader :path
|
49
|
+
|
50
|
+
def initialize(path)
|
51
|
+
|
52
|
+
@path = path.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
# Locking is successful if this Ruby process can create and lock
|
56
|
+
# its lockfile (at the given path).
|
57
|
+
#
|
58
|
+
def lock
|
59
|
+
|
60
|
+
return true if locked?
|
61
|
+
|
62
|
+
@lockfile = nil
|
63
|
+
|
64
|
+
FileUtils.mkdir_p(::File.dirname(@path))
|
65
|
+
|
66
|
+
file = File.new(@path, File::RDWR | File::CREAT)
|
67
|
+
locked = file.flock(File::LOCK_NB | File::LOCK_EX)
|
68
|
+
|
69
|
+
return false unless locked
|
70
|
+
|
71
|
+
now = Time.now
|
72
|
+
|
73
|
+
file.print("pid: #{$$}, ")
|
74
|
+
file.print("scheduler.object_id: #{self.object_id}, ")
|
75
|
+
file.print("time: #{now}, ")
|
76
|
+
file.print("timestamp: #{now.to_f}")
|
77
|
+
file.flush
|
78
|
+
|
79
|
+
@lockfile = file
|
80
|
+
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def unlock
|
85
|
+
|
86
|
+
!! (@lockfile && @lockfile.flock(File::LOCK_UN))
|
87
|
+
end
|
88
|
+
|
89
|
+
def locked?
|
90
|
+
|
91
|
+
!! (@lockfile && @lockfile.flock(File::LOCK_NB | File::LOCK_EX))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
data/lib/rufus/scheduler/util.rb
CHANGED
data/spec/basics_spec.rb
CHANGED
@@ -19,17 +19,22 @@ describe 'basics' do
|
|
19
19
|
|
20
20
|
it 'accepts a timezone final argument' do
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
if jruby? or ruby18?
|
23
|
+
|
24
|
+
expect(true).to be(true)
|
25
|
+
|
26
|
+
else
|
27
|
+
|
28
|
+
expect(
|
29
|
+
tts(Time.new(2014, 1, 1, 1, 0, 0, '+01:00'))
|
30
|
+
).to eq('2014-01-01 01:00:00 +0100')
|
31
|
+
expect(
|
32
|
+
tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
|
33
|
+
).to eq('2014-08-01 01:00:00 +0100')
|
34
|
+
expect(
|
35
|
+
tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
|
36
|
+
).to eq('2014-08-01 01:00:00 +0100')
|
37
|
+
end
|
33
38
|
end
|
34
39
|
end
|
35
40
|
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Sat Aug 16 05:43:06 JST 2014
|
6
|
+
# added by @ecin
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'spec_helper'
|
10
|
+
|
11
|
+
|
12
|
+
describe Rufus::Scheduler::FileLock do
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
|
16
|
+
@lock_path = '.rufus-scheduler.lock'
|
17
|
+
@lock = Rufus::Scheduler::FileLock.new(@lock_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
after :each do
|
21
|
+
|
22
|
+
FileUtils.rm_f(@lock_path)
|
23
|
+
FileUtils.rm_f('lock.txt')
|
24
|
+
end
|
25
|
+
|
26
|
+
context ':scheduler_lock => Rufus::Scheduler::FileLock.new(path)' do
|
27
|
+
|
28
|
+
it 'writes down a .rufus-scheduler.lock file' do
|
29
|
+
|
30
|
+
@lock.lock
|
31
|
+
|
32
|
+
line = File.read(@lock_path)
|
33
|
+
|
34
|
+
expect(line).to match(/pid: #{$$}/)
|
35
|
+
end
|
36
|
+
|
37
|
+
it '"flocks" the lock file' do
|
38
|
+
|
39
|
+
@lock.lock
|
40
|
+
|
41
|
+
f = File.new(@lock_path, 'a')
|
42
|
+
|
43
|
+
expect(f.flock(File::LOCK_NB | File::LOCK_EX)).to eq(false)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
File without changes
|
data/spec/lock_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Sat Aug 16 05:42:11 JST 2014
|
6
|
+
# added by @ecin
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'spec_helper'
|
10
|
+
|
11
|
+
|
12
|
+
describe Rufus::Scheduler do
|
13
|
+
|
14
|
+
context "when running multiple schedulers side-by-side" do
|
15
|
+
|
16
|
+
class AlwaysLock
|
17
|
+
def lock; true; end
|
18
|
+
def unlock; true; end
|
19
|
+
def locked?; true; end
|
20
|
+
end
|
21
|
+
|
22
|
+
class NeverLock
|
23
|
+
def lock; false; end
|
24
|
+
def unlock; true; end
|
25
|
+
def locked?; true; end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "only starts if it can acquire a scheduler lock" do
|
29
|
+
|
30
|
+
main = Rufus::Scheduler.new :scheduler_lock => AlwaysLock.new
|
31
|
+
backup = Rufus::Scheduler.new :scheduler_lock => NeverLock.new
|
32
|
+
|
33
|
+
expect(main).to be_up
|
34
|
+
expect(backup).to be_down
|
35
|
+
end
|
36
|
+
|
37
|
+
it "only triggers jobs when it can acquire a trigger lock" do
|
38
|
+
|
39
|
+
main = Rufus::Scheduler.new(:trigger_lock => AlwaysLock.new)
|
40
|
+
backup = Rufus::Scheduler.new(:trigger_lock => NeverLock.new)
|
41
|
+
|
42
|
+
expect(main).to be_up
|
43
|
+
expect(backup).to be_up
|
44
|
+
|
45
|
+
counter = 0
|
46
|
+
job = proc { counter += 1 }
|
47
|
+
main.schedule_in(0, job)
|
48
|
+
backup.schedule_in(0, job)
|
49
|
+
|
50
|
+
sleep 0.5
|
51
|
+
|
52
|
+
expect(main.jobs).to be_empty
|
53
|
+
expect(backup.jobs.count).to eq(1)
|
54
|
+
expect(backup.jobs.first.next_time).to be(false)
|
55
|
+
expect(counter).to eq(1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/spec/parse_spec.rb
CHANGED
@@ -47,6 +47,10 @@ describe Rufus::Scheduler do
|
|
47
47
|
expect(parse('Japan Sun Nov 18 16:01:00 2012').getutc.strftime('%c')).to eq(
|
48
48
|
'Sun Nov 18 07:01:00 2012'
|
49
49
|
)
|
50
|
+
|
51
|
+
expect(parse('Sun Nov 18 16:01:00 2012 America/New_York').getutc.strftime('%c')).to eq(
|
52
|
+
'Sun Nov 18 21:01:00 2012'
|
53
|
+
)
|
50
54
|
end
|
51
55
|
|
52
56
|
it 'parses datetimes with named timezones' do
|
data/spec/scheduler_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tzinfo
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- Rakefile
|
86
86
|
- lib/rufus-scheduler.rb
|
87
87
|
- lib/rufus/scheduler.rb
|
88
|
+
- lib/rufus/scheduler/locks.rb
|
88
89
|
- lib/rufus/scheduler/cronline.rb
|
89
90
|
- lib/rufus/scheduler/util.rb
|
90
91
|
- lib/rufus/scheduler/jobs.rb
|
@@ -97,20 +98,22 @@ files:
|
|
97
98
|
- spec/job_at_spec.rb
|
98
99
|
- spec/schedule_at_spec.rb
|
99
100
|
- spec/error_spec.rb
|
101
|
+
- spec/lock_spec.rb
|
100
102
|
- spec/schedule_cron_spec.rb
|
101
103
|
- spec/job_interval_spec.rb
|
102
104
|
- spec/job_repeat_spec.rb
|
103
|
-
- spec/lockfile_spec.rb
|
104
105
|
- spec/schedule_every_spec.rb
|
105
106
|
- spec/threads_spec.rb
|
106
107
|
- spec/cronline_spec.rb
|
108
|
+
- spec/lock_lockfile_spec.rb
|
107
109
|
- spec/job_in_spec.rb
|
108
110
|
- spec/parse_spec.rb
|
109
111
|
- spec/scheduler_spec.rb
|
110
|
-
- spec/
|
112
|
+
- spec/lock_custom_spec.rb
|
111
113
|
- spec/basics_spec.rb
|
112
114
|
- spec/job_cron_spec.rb
|
113
115
|
- spec/job_every_spec.rb
|
116
|
+
- spec/lock_flock_spec.rb
|
114
117
|
- rufus-scheduler.gemspec
|
115
118
|
- CHANGELOG.txt
|
116
119
|
- TODO.txt
|
@@ -120,7 +123,7 @@ files:
|
|
120
123
|
homepage: http://github.com/jmettraux/rufus-scheduler
|
121
124
|
licenses:
|
122
125
|
- MIT
|
123
|
-
post_install_message: ! "\n***\n\nThanks for installing rufus-scheduler 3.0.
|
126
|
+
post_install_message: ! "\n***\n\nThanks for installing rufus-scheduler 3.0.9\n\nIt
|
124
127
|
might not be 100% compatible with rufus-scheduler 2.x.\n\nIf you encounter issues
|
125
128
|
with this new rufus-scheduler, especially\nif your app worked fine with previous
|
126
129
|
versions of it, you can\n\nA) Forget it and peg your Gemfile to rufus-scheduler
|