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.
@@ -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
@@ -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
 
@@ -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.8'
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
- lock || return
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} lockfile: #{@lockfile.inspect}")
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 }
@@ -117,15 +117,16 @@ module Rufus
117
117
 
118
118
  def trigger(time)
119
119
 
120
- set_next_time(false, time)
120
+ set_next_time(time)
121
121
 
122
- return if opts[:overlap] == false && running?
123
-
124
- r =
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(true, 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(is_post, trigger_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(false, nil)
531
+ set_next_time(nil)
531
532
  end
532
533
 
533
534
  protected
534
535
 
535
- def set_next_time(is_post, trigger_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(false, nil)
571
+ set_next_time(nil)
571
572
  end
572
573
 
573
574
  protected
574
575
 
575
- def set_next_time(is_post, trigger_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(is_post, trigger_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
+
@@ -46,7 +46,7 @@ module Rufus
46
46
  o.is_a?(String) ? parse_duration(o, opts) : o
47
47
  end
48
48
 
49
- TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9\-+]+)?)\b/
49
+ TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9_\-+]+)?)\b/
50
50
 
51
51
  def self.parse_at(o, opts={})
52
52
 
@@ -19,17 +19,22 @@ describe 'basics' do
19
19
 
20
20
  it 'accepts a timezone final argument' do
21
21
 
22
- pending if jruby? or ruby18?
23
-
24
- expect(
25
- tts(Time.new(2014, 1, 1, 1, 0, 0, '+01:00'))
26
- ).to eq('2014-01-01 01:00:00 +0100')
27
- expect(
28
- tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
29
- ).to eq('2014-08-01 01:00:00 +0100')
30
- expect(
31
- tts(Time.new(2014, 8, 1, 1, 0, 0, '+01:00'))
32
- ).to eq('2014-08-01 01:00:00 +0100')
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
 
@@ -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
+
@@ -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
+
@@ -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
@@ -540,7 +540,7 @@ describe Rufus::Scheduler do
540
540
  sleep 3
541
541
  end
542
542
 
543
- sleep 0.4
543
+ sleep 0.49
544
544
 
545
545
  expect(@scheduler.running_jobs(:tag => 't0').map(&:original)).to eq(
546
546
  %w[ 0.1s ]
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.8
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-06-08 00:00:00.000000000 Z
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/custom_locks_spec.rb
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.8\n\nIt
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