rufus-scheduler 3.5.1 → 3.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +32 -0
- data/CREDITS.md +14 -4
- data/LICENSE.txt +1 -1
- data/Makefile +1 -1
- data/README.md +174 -84
- data/lib/rufus/scheduler.rb +528 -460
- data/lib/rufus/scheduler/job_array.rb +37 -47
- data/lib/rufus/scheduler/jobs_core.rb +369 -0
- data/lib/rufus/scheduler/jobs_one_time.rb +53 -0
- data/lib/rufus/scheduler/jobs_repeat.rb +333 -0
- data/lib/rufus/scheduler/locks.rb +41 -44
- data/lib/rufus/scheduler/util.rb +166 -150
- data/rufus-scheduler.gemspec +12 -3
- metadata +14 -9
- data/lib/rufus/scheduler/jobs.rb +0 -646
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 86f0ae4ebefa9cf941f66efb56041515eea96cb5105289d9f0f54899841cffc6
|
4
|
+
data.tar.gz: 9e6d1422b91536aa56cc2cdb627f3c88e21748c8e8734ba2eb929a46912f303e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45667cceb3f382ac71b7158d2884fbde21c9ac6f3027889a1dd8b7fd855bd014b35a1a4180b93118552aa7e6e08df061259113b1a5ce86f4e892a4b2f8c0436e
|
7
|
+
data.tar.gz: 9ef9d0926f33bacdb0c2b8727b801d861db960ba4b6efac28642ea27e578c1de60a6b1b144217cace6c17de759100b0229c42ba79bb9db4b40527c1e8cdac8e4
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,38 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
### rufus-scheduler 3.8.0 - released 2021-07-14
|
6
|
+
|
7
|
+
* Add #source_location to Job, gh-322
|
8
|
+
|
9
|
+
|
10
|
+
### rufus-scheduler 3.7.0 - released 2020-12-31
|
11
|
+
|
12
|
+
* Implement Job name:/n: #name and #name=, gh-309
|
13
|
+
* Add Job #has_key?, #value, and #entries
|
14
|
+
* Add #locals access to Job
|
15
|
+
* Implement Scheduler#around_trigger, @jjb, gh-310
|
16
|
+
* Accept max_worker_threads: for max_work_threads:
|
17
|
+
* Clean up Scheduler#shutdwon, thanks @itsaphel and @jjb, gh-304, gh-315
|
18
|
+
|
19
|
+
* f59df40 Bring in discard_past: for every jobs, gh-290
|
20
|
+
* 7613277 Introduce :discard_past = false for cron, gh-305
|
21
|
+
|
22
|
+
|
23
|
+
### rufus-scheduler 3.6.0 - released 2019-04-22
|
24
|
+
|
25
|
+
* Let Scheduler#cron fail if the cron string is invalid, gh-289
|
26
|
+
* Implement Job#next_times(count) for cron, every, and interval jobs
|
27
|
+
* Implement Job#next_times(count) for at and in jobs
|
28
|
+
* Stop fooling around and stick to https://semver.org
|
29
|
+
|
30
|
+
|
31
|
+
### rufus-scheduler 3.5.2 - released 2018-08-01
|
32
|
+
|
33
|
+
* Use Fugit::Cron#rough_frequency
|
34
|
+
* Improve Job#check_frequency performance, gh-276, @drcapulet
|
35
|
+
|
36
|
+
|
5
37
|
### rufus-scheduler 3.5.1 - released 2018-07-20
|
6
38
|
|
7
39
|
* Upgrade fugit to 1.1.4 (with out of DST issue fix)
|
data/CREDITS.md
CHANGED
@@ -4,10 +4,18 @@
|
|
4
4
|
|
5
5
|
## Contributors
|
6
6
|
|
7
|
-
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
7
|
+
* John Bachir https://github.com/jjb gh-310
|
8
|
+
* Daniel Berger https://github.com/djberg96 gh-300
|
9
|
+
* Ceyhun Onur https://github.com/ceyonur parse_cron no_error: true
|
10
|
+
* Darwin Wu https://github.com/dwaxe Rails initializer vs tests change
|
11
|
+
* Mike Karolow https://github.com/mike-yesware update Travis target Rubies
|
12
|
+
* Jack-Nie https://github.com/jack-nie gh-285 fix broken comment link
|
13
|
+
* Yechiel Kalmenson (https://github.com/achasveachas) README link fix
|
14
|
+
* Alex Coomans (https://github.com/drcapulet) gh-276 freq check pref improvement
|
15
|
+
* Vais Salikhov (https://github.com/vais) many document clarifications
|
16
|
+
* Wes McNamee (https://github.com/ghostsquad) let #schedule accept a CronLine
|
17
|
+
* Joe Rafaniello (https://github.com/jrafanie) Travis Ruby 2.4.1
|
18
|
+
* Benjamin Fleischer (https://github.com/bf4) ZoTime#subtract
|
11
19
|
* Sam Rowe (https://github.com/riddley) gh-240 timezone for Debian
|
12
20
|
* Daniel Rodgers-Pryor (https://github.com/djrodgerspryor), gh-238 fix ZooKeeper example
|
13
21
|
* Cody Cutrer (https://github.com/ccutrer) gh-232 is_a?(Fixnum) replacement
|
@@ -59,6 +67,8 @@
|
|
59
67
|
|
60
68
|
## Feedback
|
61
69
|
|
70
|
+
* aphel (https://github.com/itsaphel) #shutdown vs current thread, gh-304
|
71
|
+
* aesyondu (https://github.com/aesyondu) Rails console 4.2.x, gh-186
|
62
72
|
* Sasha Hoellger (https://github.com/mitnal) parse_cron and readme, gh-270
|
63
73
|
* Gian (https://github.com/snmgian) cron vs :first clarification, gh-266
|
64
74
|
* Vito Laurenza (https://github.com/veetow) help debugging tz issues, gh-240
|
data/LICENSE.txt
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
Copyright (c) 2005-
|
2
|
+
Copyright (c) 2005-2021, John Mettraux, jmettraux@gmail.com
|
3
3
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
data/Makefile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
# rufus-scheduler
|
3
3
|
|
4
|
-
[![
|
5
|
-
[![Gem Version](https://badge.fury.io/rb/rufus-scheduler.svg)](
|
4
|
+
[![tests](https://github.com/jmettraux/rufus-scheduler/workflows/test/badge.svg)](https://github.com/jmettraux/rufus-scheduler/actions)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/rufus-scheduler.svg)](https://badge.fury.io/rb/rufus-scheduler)
|
6
|
+
[![Join the chat at https://gitter.im/floraison/fugit](https://badges.gitter.im/floraison/fugit.svg)](https://gitter.im/floraison/fugit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
6
7
|
|
7
8
|
Job scheduler for Ruby (at, cron, in and every jobs).
|
8
9
|
|
@@ -23,7 +24,11 @@ scheduler.in '3s' do
|
|
23
24
|
end
|
24
25
|
|
25
26
|
scheduler.join
|
27
|
+
#
|
26
28
|
# let the current thread join the scheduler thread
|
29
|
+
#
|
30
|
+
# (please note that this join should be removed when scheduling
|
31
|
+
# in a web application (Rails and friends) initializer)
|
27
32
|
```
|
28
33
|
(run with `ruby quickstart.rb`)
|
29
34
|
|
@@ -46,6 +51,9 @@ end
|
|
46
51
|
scheduler.every '3h' do
|
47
52
|
# do something every 3 hours
|
48
53
|
end
|
54
|
+
scheduler.every '3h10m' do
|
55
|
+
# do something every 3 hours and 10 minutes
|
56
|
+
end
|
49
57
|
|
50
58
|
scheduler.cron '5 0 * * *' do
|
51
59
|
# do something every day, five minutes after midnight
|
@@ -55,6 +63,8 @@ end
|
|
55
63
|
# ...
|
56
64
|
```
|
57
65
|
|
66
|
+
Rufus-scheduler uses [fugit](https://github.com/floraison/fugit) for parsing time strings, [et-orbi](https://github.com/floraison/et-orbi) for pairing time and [tzinfo](https://github.com/tzinfo/tzinfo) timezones.
|
67
|
+
|
58
68
|
## non-features
|
59
69
|
|
60
70
|
Rufus-scheduler (out of the box) is an in-process, in-memory scheduler. It uses threads.
|
@@ -67,9 +77,10 @@ A rufus-scheduler instance will go on scheduling while it is present among the o
|
|
67
77
|
## related and similar gems
|
68
78
|
|
69
79
|
* [Whenever](https://github.com/javan/whenever) - let cron call back your Ruby code, trusted and reliable cron drives your schedule
|
80
|
+
* [ruby-clock](https://github.com/jjb/ruby-clock) - a clock process / job scheduler for Ruby
|
70
81
|
* [Clockwork](https://github.com/Rykian/clockwork) - rufus-scheduler inspired gem
|
71
82
|
* [Crono](https://github.com/plashchynski/crono) - an in-Rails cron scheduler
|
72
|
-
* [PerfectSched](https://github.com/treasure-data/perfectsched) - highly available distributed cron built on [Sequel](
|
83
|
+
* [PerfectSched](https://github.com/treasure-data/perfectsched) - highly available distributed cron built on [Sequel](https://sequel.jeremyevans.net) and more
|
73
84
|
|
74
85
|
(please note: rufus-scheduler is not a cron replacement)
|
75
86
|
|
@@ -86,7 +97,7 @@ There is no EventMachine-based scheduler anymore.
|
|
86
97
|
I'll drive you right to the [tracks](#so-rails).
|
87
98
|
|
88
99
|
|
89
|
-
##
|
100
|
+
## notable changes:
|
90
101
|
|
91
102
|
* As said, no more EventMachine-based scheduler
|
92
103
|
* ```scheduler.every('100') {``` will schedule every 100 seconds (previously, it would have been 0.1s). This aligns rufus-scheduler with Ruby's ```sleep(100)```
|
@@ -94,8 +105,8 @@ I'll drive you right to the [tracks](#so-rails).
|
|
94
105
|
* The error_handler is [#on_error](#rufusscheduleron_errorjob-error) (instead of #on_exception), by default it now prints the details of the error to $stderr (used to be $stdout)
|
95
106
|
* Rufus::Scheduler::TimeOutError renamed to Rufus::Scheduler::TimeoutError
|
96
107
|
* Introduction of "interval" jobs. Whereas "every" jobs are like "every 10 minutes, do this", interval jobs are like "do that, then wait for 10 minutes, then do that again, and so on"
|
97
|
-
* Introduction of a :
|
98
|
-
* "discard_past" is on by default. If the scheduler (its host) sleeps for 1 hour and a
|
108
|
+
* Introduction of a lockfile: true/filename mechanism to prevent multiple schedulers from executing
|
109
|
+
* "discard_past" is on by default. If the scheduler (its host) sleeps for 1 hour and a `every '10m'` job is on, it will trigger once at wakeup, not 6 times (discard_past was false by default in rufus-scheduler 2.x). No intention to re-introduce `discard_past: false` in 3.0 for now.
|
99
110
|
* Introduction of Scheduler #on_pre_trigger and #on_post_trigger callback points
|
100
111
|
|
101
112
|
|
@@ -105,26 +116,26 @@ So you need help. People can help you, but first help them help you, and don't w
|
|
105
116
|
|
106
117
|
"hello", "please" and "thanks" are not swear words.
|
107
118
|
|
108
|
-
Go read [how to report bugs effectively](
|
119
|
+
Go read [how to report bugs effectively](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html), twice.
|
109
120
|
|
110
121
|
Update: [help_help.md](https://gist.github.com/jmettraux/310fed75f568fd731814) might help help you.
|
111
122
|
|
112
|
-
### on
|
123
|
+
### on Gitter
|
113
124
|
|
114
|
-
|
125
|
+
You can find help via chat over at [https://gitter.im/floraison/fugit](https://gitter.im/floraison/fugit). It's [fugit](https://github.com/floraison/fugit), [et-orbi](https://github.com/floraison/et-orbi), and rufus-scheduler combined chat room.
|
115
126
|
|
116
|
-
Please
|
127
|
+
Please be courteous.
|
117
128
|
|
118
129
|
### issues
|
119
130
|
|
120
|
-
Yes, issues can be reported in [rufus-scheduler issues](https://github.com/jmettraux/rufus-scheduler/issues), I'd actually prefer bugs in there. If there is nothing wrong with rufus-scheduler, a [Stack Overflow question](
|
131
|
+
Yes, issues can be reported in [rufus-scheduler issues](https://github.com/jmettraux/rufus-scheduler/issues), I'd actually prefer bugs in there. If there is nothing wrong with rufus-scheduler, a [Stack Overflow question](https://stackoverflow.com/questions/ask?tags=rufus-scheduler+ruby) is better.
|
121
132
|
|
122
133
|
### faq
|
123
134
|
|
124
|
-
* [It doesn't work...](
|
125
|
-
* [I want a refund](
|
126
|
-
* [Passenger and rufus-scheduler](
|
127
|
-
* [Passenger and rufus-scheduler (2)](
|
135
|
+
* [It doesn't work...](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html)
|
136
|
+
* [I want a refund](https://blog.nodejitsu.com/getting-refunds-on-open-source-projects)
|
137
|
+
* [Passenger and rufus-scheduler](https://stackoverflow.com/questions/18108719/debugging-rufus-scheduler/18156180#18156180)
|
138
|
+
* [Passenger and rufus-scheduler (2)](https://stackoverflow.com/questions/21861387/rufus-cron-job-not-working-in-apache-passenger#answer-21868555)
|
128
139
|
* [Passenger in-depth spawn methods](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/)
|
129
140
|
* [Passenger in-depth spawn methods (smart spawning)](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#smart-spawning-hooks)
|
130
141
|
* [The scheduler comes up when running the Rails console or a Rake task](https://github.com/jmettraux/rufus-scheduler#avoid-scheduling-when-running-the-ruby-on-rails-console)
|
@@ -212,7 +223,7 @@ job =
|
|
212
223
|
# also
|
213
224
|
|
214
225
|
job =
|
215
|
-
scheduler.in '10d', :
|
226
|
+
scheduler.in '10d', job: true do
|
216
227
|
# ...
|
217
228
|
end
|
218
229
|
```
|
@@ -367,23 +378,40 @@ While paused, the scheduler still accepts schedules, but no schedule will get tr
|
|
367
378
|
|
368
379
|
## job options
|
369
380
|
|
370
|
-
### :
|
381
|
+
### name: string
|
371
382
|
|
372
|
-
|
383
|
+
Sets the name of the job.
|
373
384
|
|
374
|
-
|
385
|
+
```ruby
|
386
|
+
scheduler.cron '*/15 8 * * *', name: 'Robert' do |job|
|
387
|
+
puts "A, it's #{Time.now} and my name is #{job.name}"
|
388
|
+
end
|
389
|
+
|
390
|
+
job1 =
|
391
|
+
scheduler.schedule_cron '*/30 9 * * *', n: 'temporary' do |job|
|
392
|
+
puts "B, it's #{Time.now} and my name is #{job.name}"
|
393
|
+
end
|
394
|
+
# ...
|
395
|
+
job1.name = 'Beowulf'
|
396
|
+
```
|
397
|
+
|
398
|
+
### blocking: true
|
399
|
+
|
400
|
+
By default, jobs are triggered in their own, new threads. When `blocking: true`, the job is triggered in the scheduler thread (a new thread is not created). Yes, while a blocking job is running, the scheduler is not scheduling.
|
401
|
+
|
402
|
+
### overlap: false
|
375
403
|
|
376
404
|
Since, by default, jobs are triggered in their own new threads, job instances might overlap. For example, a job that takes 10 minutes and is scheduled every 7 minutes will have overlaps.
|
377
405
|
|
378
|
-
To prevent overlap, one can set
|
406
|
+
To prevent overlap, one can set `overlap: false`. Such a job will not trigger if one of its instances is already running.
|
379
407
|
|
380
408
|
The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
|
381
409
|
|
382
|
-
### :
|
410
|
+
### mutex: mutex_instance / mutex_name / array of mutexes
|
383
411
|
|
384
412
|
When a job with a mutex triggers, the job's block is executed with the mutex around it, preventing other jobs with the same mutex from entering (it makes the other jobs wait until it exits the mutex).
|
385
413
|
|
386
|
-
This is different from
|
414
|
+
This is different from `overlap: false`, which is, first, limited to instances of the same job, and, second, doesn't make the incoming job instance block/wait but give up.
|
387
415
|
|
388
416
|
`:mutex` accepts a mutex instance or a mutex name (String). It also accept an array of mutex names / mutex instances. It allows for complex relations between jobs.
|
389
417
|
|
@@ -393,12 +421,12 @@ Note: creating lots of different mutexes is OK. Rufus-scheduler will place them
|
|
393
421
|
|
394
422
|
The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
|
395
423
|
|
396
|
-
### :
|
424
|
+
### timeout: duration or point in time
|
397
425
|
|
398
426
|
It's OK to specify a timeout when scheduling some work. After the time specified, it gets interrupted via a Rufus::Scheduler::TimeoutError.
|
399
427
|
|
400
428
|
```ruby
|
401
|
-
scheduler.in '10d', :
|
429
|
+
scheduler.in '10d', timeout: '1d' do
|
402
430
|
begin
|
403
431
|
# ... do something
|
404
432
|
rescue Rufus::Scheduler::TimeoutError
|
@@ -419,15 +447,15 @@ In the case of an "every" job, this will be the first time (modulo the scheduler
|
|
419
447
|
For a "cron" job as well, the :first will point to the first time the job has to trigger, the following trigger times are then determined by the cron string.
|
420
448
|
|
421
449
|
```ruby
|
422
|
-
scheduler.every '2d', :
|
450
|
+
scheduler.every '2d', first_at: Time.now + 10 * 3600 do
|
423
451
|
# ... every two days, but start in 10 hours
|
424
452
|
end
|
425
453
|
|
426
|
-
scheduler.every '2d', :
|
454
|
+
scheduler.every '2d', first_in: '10h' do
|
427
455
|
# ... every two days, but start in 10 hours
|
428
456
|
end
|
429
457
|
|
430
|
-
scheduler.cron '00 14 * * *', :
|
458
|
+
scheduler.cron '00 14 * * *', first_in: '3d' do
|
431
459
|
# ... every day at 14h00, but start after 3 * 24 hours
|
432
460
|
end
|
433
461
|
```
|
@@ -449,12 +477,11 @@ s = Rufus::Scheduler.new
|
|
449
477
|
|
450
478
|
n = Time.now; p [ :scheduled_at, n, n.to_f ]
|
451
479
|
|
452
|
-
s.every '3s', :
|
480
|
+
s.every '3s', first: :now do
|
453
481
|
n = Time.now; p [ :in, n, n.to_f ]
|
454
482
|
end
|
455
483
|
|
456
484
|
s.join
|
457
|
-
|
458
485
|
```
|
459
486
|
|
460
487
|
that'll output something like:
|
@@ -475,15 +502,15 @@ This option is for repeat jobs (cron / every) only.
|
|
475
502
|
It indicates the point in time after which the job should unschedule itself.
|
476
503
|
|
477
504
|
```ruby
|
478
|
-
scheduler.cron '5 23 * * *', :
|
505
|
+
scheduler.cron '5 23 * * *', last_in: '10d' do
|
479
506
|
# ... do something every evening at 23:05 for 10 days
|
480
507
|
end
|
481
508
|
|
482
|
-
scheduler.every '10m', :
|
509
|
+
scheduler.every '10m', last_at: Time.now + 10 * 3600 do
|
483
510
|
# ... do something every 10 minutes for 10 hours
|
484
511
|
end
|
485
512
|
|
486
|
-
scheduler.every '10m', :
|
513
|
+
scheduler.every '10m', last_in: 10 * 3600 do
|
487
514
|
# ... do something every 10 minutes for 10 hours
|
488
515
|
end
|
489
516
|
```
|
@@ -498,16 +525,16 @@ job.last_at = Rufus::Scheduler.parse('2029-12-12')
|
|
498
525
|
# set the last bound
|
499
526
|
```
|
500
527
|
|
501
|
-
### :
|
528
|
+
### times: nb of times (before auto-unscheduling)
|
502
529
|
|
503
530
|
One can tell how many times a repeat job (CronJob or EveryJob) is to execute before unscheduling by itself.
|
504
531
|
|
505
532
|
```ruby
|
506
|
-
scheduler.every '2d', :
|
533
|
+
scheduler.every '2d', times: 10 do
|
507
534
|
# ... do something every two days, but not more than 10 times
|
508
535
|
end
|
509
536
|
|
510
|
-
scheduler.cron '0 23 * * *', :
|
537
|
+
scheduler.cron '0 23 * * *', times: 31 do
|
511
538
|
# ... do something every day at 23:00 but do it no more than 31 times
|
512
539
|
end
|
513
540
|
```
|
@@ -515,7 +542,7 @@ end
|
|
515
542
|
It's OK to assign nil to :times to make sure the repeat job is not limited. It's useful when the :times is determined at scheduling time.
|
516
543
|
|
517
544
|
```ruby
|
518
|
-
scheduler.cron '0 23 * * *', :
|
545
|
+
scheduler.cron '0 23 * * *', times: (nolimit ? nil : 10) do
|
519
546
|
# ...
|
520
547
|
end
|
521
548
|
```
|
@@ -537,7 +564,7 @@ job.times = 10
|
|
537
564
|
|
538
565
|
## Job methods
|
539
566
|
|
540
|
-
When calling a schedule method, the id (String) of the job is returned. Longer schedule methods return Job instances directly. Calling the shorter schedule methods with the :
|
567
|
+
When calling a schedule method, the id (String) of the job is returned. Longer schedule methods return Job instances directly. Calling the shorter schedule methods with the `job: true` also returns Job instances instead of Job ids (Strings).
|
541
568
|
|
542
569
|
```ruby
|
543
570
|
require 'rufus-scheduler'
|
@@ -555,7 +582,7 @@ When calling a schedule method, the id (String) of the job is returned. Longer s
|
|
555
582
|
end
|
556
583
|
|
557
584
|
job =
|
558
|
-
scheduler.in '1w', :
|
585
|
+
scheduler.in '1w', job: true do
|
559
586
|
# ...
|
560
587
|
end
|
561
588
|
```
|
@@ -581,7 +608,7 @@ Returns the scheduler instance itself.
|
|
581
608
|
Returns the options passed at the Job creation.
|
582
609
|
|
583
610
|
```ruby
|
584
|
-
job = scheduler.schedule_in('10d', :
|
611
|
+
job = scheduler.schedule_in('10d', tag: 'hello') do; end
|
585
612
|
job.opts
|
586
613
|
# => { :tag => 'hello' }
|
587
614
|
```
|
@@ -591,7 +618,7 @@ job.opts
|
|
591
618
|
Returns the original schedule.
|
592
619
|
|
593
620
|
```ruby
|
594
|
-
job = scheduler.schedule_in('10d', :
|
621
|
+
job = scheduler.schedule_in('10d', tag: 'hello') do; end
|
595
622
|
job.original
|
596
623
|
# => '10d'
|
597
624
|
```
|
@@ -638,12 +665,30 @@ job.callable
|
|
638
665
|
# => #<MyHandler:0x0000000163ae88 @counter=0>
|
639
666
|
```
|
640
667
|
|
668
|
+
### source_location
|
669
|
+
|
670
|
+
Added to rufus-scheduler 3.8.0.
|
671
|
+
|
672
|
+
Returns the array `[ 'path/to/file.rb', 123 ]` like `Proc#source_location` does.
|
673
|
+
|
674
|
+
```ruby
|
675
|
+
require 'rufus-scheduler'
|
676
|
+
|
677
|
+
scheduler = Rufus::Scheduler.new
|
678
|
+
|
679
|
+
job = scheduler.schedule_every('2h') { p Time.now }
|
680
|
+
|
681
|
+
p job.source_location
|
682
|
+
# ==> [ '/home/jmettraux/rufus-scheduler/test.rb', 6 ]
|
683
|
+
|
684
|
+
```
|
685
|
+
|
641
686
|
### scheduled_at
|
642
687
|
|
643
688
|
Returns the Time instance when the job got created.
|
644
689
|
|
645
690
|
```ruby
|
646
|
-
job = scheduler.schedule_in('10d', :
|
691
|
+
job = scheduler.schedule_in('10d', tag: 'hello') do; end
|
647
692
|
job.scheduled_at
|
648
693
|
# => 2013-07-17 23:48:54 +0900
|
649
694
|
```
|
@@ -684,6 +729,12 @@ The job keeps track of how long its work was in the `last_work_time` attribute.
|
|
684
729
|
|
685
730
|
The attribute `mean_work_time` contains a computed mean work time. It's recomputed after every run (if it's a repeat job).
|
686
731
|
|
732
|
+
### next_times(n)
|
733
|
+
|
734
|
+
Returns an array of `EtOrbi::EoTime` instances (Time instances with a designated time zone), listing the `n` next occurrences for this job.
|
735
|
+
|
736
|
+
Please note that for "interval" jobs, a mean work time is computed each time and it's used by this `#next_times(n)` method to approximate the next times beyond the immediate next time.
|
737
|
+
|
687
738
|
### unschedule
|
688
739
|
|
689
740
|
Unschedule the job, preventing it from firing again and removing it from the schedule. This doesn't prevent a running thread for this job to run until its end.
|
@@ -740,14 +791,14 @@ job = scheduler.schedule_in('10d') do; end
|
|
740
791
|
job.tags
|
741
792
|
# => []
|
742
793
|
|
743
|
-
job = scheduler.schedule_in('10d', :
|
794
|
+
job = scheduler.schedule_in('10d', tag: 'hello') do; end
|
744
795
|
job.tags
|
745
796
|
# => [ 'hello' ]
|
746
797
|
```
|
747
798
|
|
748
|
-
### []=, [], key
|
799
|
+
### []=, [], key?, has_key?, keys, values, and entries
|
749
800
|
|
750
|
-
Threads have thread-local variables
|
801
|
+
Threads have thread-local variables, similarly Rufus-scheduler jobs have job-local variables. Those are more like a dict with thread-safe access.
|
751
802
|
|
752
803
|
```ruby
|
753
804
|
job =
|
@@ -762,13 +813,29 @@ sleep 3.6
|
|
762
813
|
job[:counter]
|
763
814
|
# => 3
|
764
815
|
|
765
|
-
job.key?(:timestamp)
|
766
|
-
|
767
|
-
job.keys
|
768
|
-
# => [ :timestamp, :counter ]
|
816
|
+
job.key?(:timestamp) # => true
|
817
|
+
job.has_key?(:timestamp) # => true
|
818
|
+
job.keys # => [ :timestamp, :counter ]
|
769
819
|
```
|
770
820
|
|
771
|
-
|
821
|
+
Locals can be set at schedule time:
|
822
|
+
```ruby
|
823
|
+
job0 =
|
824
|
+
@scheduler.schedule_cron '*/15 12 * * *', locals: { a: 0 } do
|
825
|
+
# ...
|
826
|
+
end
|
827
|
+
job1 =
|
828
|
+
@scheduler.schedule_cron '*/15 13 * * *', l: { a: 1 } do
|
829
|
+
# ...
|
830
|
+
end
|
831
|
+
```
|
832
|
+
|
833
|
+
One can fetch the Hash directly with `Job#locals`. Of course, direct manipulation is not thread-safe.
|
834
|
+
```ruby
|
835
|
+
job.locals.entries do |k, v|
|
836
|
+
p "#{k}: #{v}"
|
837
|
+
end
|
838
|
+
```
|
772
839
|
|
773
840
|
### call
|
774
841
|
|
@@ -909,24 +976,24 @@ Here is an example:
|
|
909
976
|
scheduler.at_jobs.each(&:unschedule)
|
910
977
|
```
|
911
978
|
|
912
|
-
### Scheduler#jobs(:
|
979
|
+
### Scheduler#jobs(tag: / tags: x)
|
913
980
|
|
914
981
|
When scheduling a job, one can specify one or more tags attached to the job. These can be used to look up the job later on.
|
915
982
|
|
916
983
|
```ruby
|
917
|
-
scheduler.in '10d', :
|
984
|
+
scheduler.in '10d', tag: 'main_process' do
|
918
985
|
# ...
|
919
986
|
end
|
920
|
-
scheduler.in '10d', :
|
987
|
+
scheduler.in '10d', tags: [ 'main_process', 'side_dish' ] do
|
921
988
|
# ...
|
922
989
|
end
|
923
990
|
|
924
991
|
# ...
|
925
992
|
|
926
|
-
jobs = scheduler.jobs(:
|
993
|
+
jobs = scheduler.jobs(tag: 'main_process')
|
927
994
|
# find all the jobs with the 'main_process' tag
|
928
995
|
|
929
|
-
jobs = scheduler.jobs(:
|
996
|
+
jobs = scheduler.jobs(tags: [ 'main_process', 'side_dish' ]
|
930
997
|
# find all the jobs with the 'main_process' AND 'side_dish' tags
|
931
998
|
```
|
932
999
|
|
@@ -951,6 +1018,10 @@ Shuts down the scheduler, ceases any scheduler/triggering activity.
|
|
951
1018
|
|
952
1019
|
Shuts down the scheduler, waits (blocks) until all the jobs cease running.
|
953
1020
|
|
1021
|
+
### Scheduler#shutdown(wait: n)
|
1022
|
+
|
1023
|
+
Shuts down the scheduler, waits (blocks) at most n seconds until all the jobs cease running. (Jobs are killed after n seconds have elapsed).
|
1024
|
+
|
954
1025
|
### Scheduler#shutdown(:kill)
|
955
1026
|
|
956
1027
|
Kills all the job (threads) and then shuts the scheduler down. Radical.
|
@@ -973,6 +1044,8 @@ Returns since the count of seconds for which the scheduler has been running.
|
|
973
1044
|
|
974
1045
|
Lets the current thread join the scheduling thread in rufus-scheduler. The thread comes back when the scheduler gets shut down.
|
975
1046
|
|
1047
|
+
`#join` is mostly used in standalone scheduling script (or tiny one file examples). Calling `#join` from a web application initializer will probably hijack the main thread and prevent the web application from being served. Do not put a `#join` in such a web application initializer file.
|
1048
|
+
|
976
1049
|
### Scheduler#threads
|
977
1050
|
|
978
1051
|
Returns all the threads associated with the scheduler, including the scheduler thread itself.
|
@@ -985,7 +1058,7 @@ Lists the work threads associated with the scheduler. The query option defaults
|
|
985
1058
|
* :active : all the work threads currently running a Job
|
986
1059
|
* :vacant : all the work threads currently not running a Job
|
987
1060
|
|
988
|
-
Note that the main schedule thread will be returned if it is currently running a Job (ie one of those :
|
1061
|
+
Note that the main schedule thread will be returned if it is currently running a Job (ie one of those `blocking: true` jobs).
|
989
1062
|
|
990
1063
|
### Scheduler#scheduled?(job_or_job_id)
|
991
1064
|
|
@@ -993,7 +1066,7 @@ Returns true if the arg is a currently scheduled job (see Job#scheduled?).
|
|
993
1066
|
|
994
1067
|
### Scheduler#occurrences(time0, time1)
|
995
1068
|
|
996
|
-
Returns a hash
|
1069
|
+
Returns a hash `{ job => [ t0, t1, ... ] }` mapping jobs to their potential trigger time within the `[ time0, time1 ]` span.
|
997
1070
|
|
998
1071
|
Please note that, for interval jobs, the ```#mean_work_time``` is used, so the result is only a prediction.
|
999
1072
|
|
@@ -1085,7 +1158,9 @@ def scheduler.on_error(job, error)
|
|
1085
1158
|
end
|
1086
1159
|
```
|
1087
1160
|
|
1088
|
-
##
|
1161
|
+
## Callbacks
|
1162
|
+
|
1163
|
+
### Rufus::Scheduler #on_pre_trigger and #on_post_trigger callbacks
|
1089
1164
|
|
1090
1165
|
One can bind callbacks before and after jobs trigger:
|
1091
1166
|
|
@@ -1109,6 +1184,21 @@ The ```trigger_time``` is the time at which the job triggers. It might be a bit
|
|
1109
1184
|
|
1110
1185
|
Warning: these two callbacks are executed in the scheduler thread, not in the work threads (the threads where the job execution really happens).
|
1111
1186
|
|
1187
|
+
### Rufus::Scheduler#around_trigger
|
1188
|
+
|
1189
|
+
One can create an around callback which will wrap a job:
|
1190
|
+
|
1191
|
+
```ruby
|
1192
|
+
def s.around_trigger(job)
|
1193
|
+
t = Time.now
|
1194
|
+
puts "Starting job #{job.id}..."
|
1195
|
+
yield
|
1196
|
+
puts "job #{job.id} finished in #{Time.now-t} seconds."
|
1197
|
+
end
|
1198
|
+
```
|
1199
|
+
|
1200
|
+
The around callback is executed in the thread.
|
1201
|
+
|
1112
1202
|
### Rufus::Scheduler#on_pre_trigger as a guard
|
1113
1203
|
|
1114
1204
|
Returning ```false``` in on_pre_trigger will prevent the job from triggering. Returning anything else (nil, -1, true, ...) will let the job trigger.
|
@@ -1133,23 +1223,23 @@ By default, rufus-scheduler sleeps 0.300 second between every step. At each step
|
|
1133
1223
|
The :frequency option lets you change that 0.300 second to something else.
|
1134
1224
|
|
1135
1225
|
```ruby
|
1136
|
-
scheduler = Rufus::Scheduler.new(:
|
1226
|
+
scheduler = Rufus::Scheduler.new(frequency: 5)
|
1137
1227
|
```
|
1138
1228
|
|
1139
1229
|
It's OK to use a time string to specify the frequency.
|
1140
1230
|
|
1141
1231
|
```ruby
|
1142
|
-
scheduler = Rufus::Scheduler.new(:
|
1232
|
+
scheduler = Rufus::Scheduler.new(frequency: '2h10m')
|
1143
1233
|
# this scheduler will sleep 2 hours and 10 minutes between every "step"
|
1144
1234
|
```
|
1145
1235
|
|
1146
1236
|
Use with care.
|
1147
1237
|
|
1148
|
-
### :
|
1238
|
+
### lockfile: "mylockfile.txt"
|
1149
1239
|
|
1150
1240
|
This feature only works on OSes that support the flock (man 2 flock) call.
|
1151
1241
|
|
1152
|
-
Starting the scheduler with
|
1242
|
+
Starting the scheduler with ```lockfile: '.rufus-scheduler.lock'``` will make the scheduler attempt to create and lock the file ```.rufus-scheduler.lock``` in the current working directory. If that fails, the scheduler will not start.
|
1153
1243
|
|
1154
1244
|
The idea is to guarantee only one scheduler (in a group of schedulers sharing the same lockfile) is running.
|
1155
1245
|
|
@@ -1178,7 +1268,7 @@ class HostLock
|
|
1178
1268
|
end
|
1179
1269
|
|
1180
1270
|
scheduler =
|
1181
|
-
Rufus::Scheduler.new(:
|
1271
|
+
Rufus::Scheduler.new(scheduler_lock: HostLock.new('coffee.example.com'))
|
1182
1272
|
```
|
1183
1273
|
|
1184
1274
|
By default, the scheduler_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that returns true.
|
@@ -1201,7 +1291,7 @@ class PingLock
|
|
1201
1291
|
end
|
1202
1292
|
|
1203
1293
|
scheduler =
|
1204
|
-
Rufus::Scheduler.new(:
|
1294
|
+
Rufus::Scheduler.new(trigger_lock: PingLock.new('main.example.com'))
|
1205
1295
|
```
|
1206
1296
|
|
1207
1297
|
By default, the trigger_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that always returns true.
|
@@ -1215,7 +1305,7 @@ In rufus-scheduler 2.x, by default, each job triggering received its own, brand
|
|
1215
1305
|
One can set this maximum value when starting the scheduler.
|
1216
1306
|
|
1217
1307
|
```ruby
|
1218
|
-
scheduler = Rufus::Scheduler.new(:
|
1308
|
+
scheduler = Rufus::Scheduler.new(max_work_threads: 77)
|
1219
1309
|
```
|
1220
1310
|
|
1221
1311
|
It's OK to increase the :max_work_threads of a running scheduler.
|
@@ -1228,7 +1318,7 @@ scheduler.max_work_threads += 10
|
|
1228
1318
|
## Rufus::Scheduler.singleton
|
1229
1319
|
|
1230
1320
|
Do not want to store a reference to your rufus-scheduler instance?
|
1231
|
-
Then ```Rufus::Scheduler.singleton``` can help, it returns a
|
1321
|
+
Then ```Rufus::Scheduler.singleton``` can help, it returns a singleton instance of the scheduler, initialized the first time this class method is called.
|
1232
1322
|
|
1233
1323
|
```ruby
|
1234
1324
|
Rufus::Scheduler.singleton.every '10s' { puts "hello, world!" }
|
@@ -1237,8 +1327,8 @@ Rufus::Scheduler.singleton.every '10s' { puts "hello, world!" }
|
|
1237
1327
|
It's OK to pass initialization arguments (like :frequency or :max_work_threads) but they will only be taken into account the first time ```.singleton``` is called.
|
1238
1328
|
|
1239
1329
|
```ruby
|
1240
|
-
Rufus::Scheduler.singleton(:
|
1241
|
-
Rufus::Scheduler.singleton(:
|
1330
|
+
Rufus::Scheduler.singleton(max_work_threads: 77)
|
1331
|
+
Rufus::Scheduler.singleton(max_work_threads: 277) # no effect
|
1242
1332
|
```
|
1243
1333
|
|
1244
1334
|
The ```.s``` is a shortcut for ```.singleton```.
|
@@ -1287,7 +1377,7 @@ class ZookeptScheduler < Rufus::Scheduler
|
|
1287
1377
|
end
|
1288
1378
|
```
|
1289
1379
|
|
1290
|
-
This uses a [zookeeper](
|
1380
|
+
This uses a [zookeeper](https://zookeeper.apache.org/) to make sure only one scheduler in a group of distributed schedulers runs.
|
1291
1381
|
|
1292
1382
|
The methods #lock and #unlock are overridden and #confirm_lock is provided,
|
1293
1383
|
to make sure that the lock is still valid.
|
@@ -1311,6 +1401,8 @@ Warning: you may think you're heading towards "high availability" by using a tri
|
|
1311
1401
|
|
1312
1402
|
## parsing cronlines and time strings
|
1313
1403
|
|
1404
|
+
(Please note that [fugit](https://github.com/floraison/fugit) does the heavy-lifting parsing work for rufus-scheduler).
|
1405
|
+
|
1314
1406
|
Rufus::Scheduler provides a class method ```.parse``` to parse time durations and cron strings. It's what it's using when receiving schedules. One can use it directly (no need to instantiate a Scheduler).
|
1315
1407
|
|
1316
1408
|
```ruby
|
@@ -1353,7 +1445,7 @@ Rufus::Scheduler.to_duration_hash(60)
|
|
1353
1445
|
Rufus::Scheduler.to_duration_hash(62.127)
|
1354
1446
|
# => { :m => 1, :s => 2, :ms => 127 }
|
1355
1447
|
|
1356
|
-
Rufus::Scheduler.to_duration_hash(62.127, :
|
1448
|
+
Rufus::Scheduler.to_duration_hash(62.127, drop_seconds: true)
|
1357
1449
|
# => { :m => 1 }
|
1358
1450
|
```
|
1359
1451
|
|
@@ -1536,7 +1628,7 @@ class ScheController < ApplicationController
|
|
1536
1628
|
Rails.logger.info "time flies, it's now #{Time.now}"
|
1537
1629
|
end
|
1538
1630
|
|
1539
|
-
render :
|
1631
|
+
render text: "scheduled job #{job_id}"
|
1540
1632
|
end
|
1541
1633
|
end
|
1542
1634
|
```
|
@@ -1547,9 +1639,9 @@ The rufus-scheduler singleton is instantiated in the ```config/initializers/sche
|
|
1547
1639
|
|
1548
1640
|
### avoid scheduling when running the Ruby on Rails console
|
1549
1641
|
|
1550
|
-
(Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/186
|
1642
|
+
(Written in reply to [gh-186](https://github.com/jmettraux/rufus-scheduler/issues/186))
|
1551
1643
|
|
1552
|
-
If you don't want rufus-scheduler to
|
1644
|
+
If you don't want rufus-scheduler to trigger anything while running the Ruby on Rails console, running for tests/specs, or running from a Rake task, you can insert a conditional return statement before jobs are added to the scheduler instance:
|
1553
1645
|
|
1554
1646
|
```ruby
|
1555
1647
|
#
|
@@ -1559,21 +1651,19 @@ require 'rufus-scheduler'
|
|
1559
1651
|
|
1560
1652
|
s = Rufus::Scheduler.singleton
|
1561
1653
|
|
1654
|
+
return if defined?(Rails::Console) || Rails.env.test? || File.split($0).last == 'rake'
|
1655
|
+
# return if $PROGRAM_NAME.include?('spring')
|
1656
|
+
# see https://github.com/jmettraux/rufus-scheduler/issues/186
|
1562
1657
|
|
1563
|
-
|
1564
|
-
|
1565
|
-
# only schedule when not running from the Ruby on Rails console
|
1566
|
-
# or from a rake task
|
1658
|
+
# do not schedule when Rails is run from its console, for a test/spec, or
|
1659
|
+
# from a Rake task
|
1567
1660
|
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
Rails.logger.flush
|
1572
|
-
end
|
1661
|
+
s.every '1m' do
|
1662
|
+
Rails.logger.info "hello, it's #{Time.now}"
|
1663
|
+
Rails.logger.flush
|
1573
1664
|
end
|
1574
1665
|
```
|
1575
1666
|
|
1576
|
-
It should work for Ruby on Rails 3 and 4.
|
1577
1667
|
|
1578
1668
|
### rails server -d
|
1579
1669
|
|
@@ -1585,8 +1675,8 @@ I avoid running `-d` in development mode and bother about daemonizing only for p
|
|
1585
1675
|
|
1586
1676
|
These are two well crafted articles on process daemonization, please read them:
|
1587
1677
|
|
1588
|
-
*
|
1589
|
-
*
|
1678
|
+
* https://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
|
1679
|
+
* https://www.mikeperham.com/2014/07/07/use-runit/
|
1590
1680
|
|
1591
1681
|
If, anyway, you need something like `rails server -d`, why not try `bundle exec unicorn -D` instead? In my (limited) experience, it worked out of the box (well, had to add `gem 'unicorn'` to `Gemfile` first).
|
1592
1682
|
|