rufus-scheduler 3.5.2 → 3.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
 
2
2
  # rufus-scheduler
3
3
 
4
- [![Build Status](https://secure.travis-ci.org/jmettraux/rufus-scheduler.svg)](http://travis-ci.org/jmettraux/rufus-scheduler)
5
- [![Gem Version](https://badge.fury.io/rb/rufus-scheduler.svg)](http://badge.fury.io/rb/rufus-scheduler)
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
 
@@ -58,6 +63,8 @@ end
58
63
  # ...
59
64
  ```
60
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
+
61
68
  ## non-features
62
69
 
63
70
  Rufus-scheduler (out of the box) is an in-process, in-memory scheduler. It uses threads.
@@ -70,9 +77,10 @@ A rufus-scheduler instance will go on scheduling while it is present among the o
70
77
  ## related and similar gems
71
78
 
72
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
73
81
  * [Clockwork](https://github.com/Rykian/clockwork) - rufus-scheduler inspired gem
74
82
  * [Crono](https://github.com/plashchynski/crono) - an in-Rails cron scheduler
75
- * [PerfectSched](https://github.com/treasure-data/perfectsched) - highly available distributed cron built on [Sequel](http://sequel.jeremyevans.net) and more
83
+ * [PerfectSched](https://github.com/treasure-data/perfectsched) - highly available distributed cron built on [Sequel](https://sequel.jeremyevans.net) and more
76
84
 
77
85
  (please note: rufus-scheduler is not a cron replacement)
78
86
 
@@ -89,7 +97,7 @@ There is no EventMachine-based scheduler anymore.
89
97
  I'll drive you right to the [tracks](#so-rails).
90
98
 
91
99
 
92
- ## Notable changes:
100
+ ## notable changes:
93
101
 
94
102
  * As said, no more EventMachine-based scheduler
95
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)```
@@ -97,8 +105,8 @@ I'll drive you right to the [tracks](#so-rails).
97
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)
98
106
  * Rufus::Scheduler::TimeOutError renamed to Rufus::Scheduler::TimeoutError
99
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"
100
- * Introduction of a :lockfile => true/filename mechanism to prevent multiple schedulers from executing
101
- * "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.
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.
102
110
  * Introduction of Scheduler #on_pre_trigger and #on_post_trigger callback points
103
111
 
104
112
 
@@ -108,26 +116,26 @@ So you need help. People can help you, but first help them help you, and don't w
108
116
 
109
117
  "hello", "please" and "thanks" are not swear words.
110
118
 
111
- Go read [how to report bugs effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html), twice.
119
+ Go read [how to report bugs effectively](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html), twice.
112
120
 
113
121
  Update: [help_help.md](https://gist.github.com/jmettraux/310fed75f568fd731814) might help help you.
114
122
 
115
- ### on IRC
123
+ ### on Gitter
116
124
 
117
- I sometimes haunt #ruote on freenode.net. The channel is not dedicated to rufus-scheduler, so if you ask a question, first mention it's about rufus-scheduler.
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.
118
126
 
119
- Please note that I prefer helping over Stack Overflow because it's more searchable than the ruote IRC archive.
127
+ Please be courteous.
120
128
 
121
129
  ### issues
122
130
 
123
- 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](http://stackoverflow.com/questions/ask?tags=rufus-scheduler+ruby) is better.
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.
124
132
 
125
133
  ### faq
126
134
 
127
- * [It doesn't work...](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html)
128
- * [I want a refund](http://blog.nodejitsu.com/getting-refunds-on-open-source-projects)
129
- * [Passenger and rufus-scheduler](http://stackoverflow.com/questions/18108719/debugging-rufus-scheduler/18156180#18156180)
130
- * [Passenger and rufus-scheduler (2)](http://stackoverflow.com/questions/21861387/rufus-cron-job-not-working-in-apache-passenger#answer-21868555)
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)
131
139
  * [Passenger in-depth spawn methods](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/)
132
140
  * [Passenger in-depth spawn methods (smart spawning)](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/#smart-spawning-hooks)
133
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)
@@ -215,7 +223,7 @@ job =
215
223
  # also
216
224
 
217
225
  job =
218
- scheduler.in '10d', :job => true do
226
+ scheduler.in '10d', job: true do
219
227
  # ...
220
228
  end
221
229
  ```
@@ -370,23 +378,40 @@ While paused, the scheduler still accepts schedules, but no schedule will get tr
370
378
 
371
379
  ## job options
372
380
 
373
- ### :blocking => true
381
+ ### name: string
382
+
383
+ Sets the name of the job.
384
+
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
374
399
 
375
- 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.
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.
376
401
 
377
- ### :overlap => false
402
+ ### overlap: false
378
403
 
379
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.
380
405
 
381
- To prevent overlap, one can set `:overlap => false`. Such a job will not trigger if one of its instances is already running.
406
+ To prevent overlap, one can set `overlap: false`. Such a job will not trigger if one of its instances is already running.
382
407
 
383
408
  The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
384
409
 
385
- ### :mutex => mutex_instance / mutex_name / array of mutexes
410
+ ### mutex: mutex_instance / mutex_name / array of mutexes
386
411
 
387
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).
388
413
 
389
- 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.
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.
390
415
 
391
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.
392
417
 
@@ -396,12 +421,12 @@ Note: creating lots of different mutexes is OK. Rufus-scheduler will place them
396
421
 
397
422
  The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
398
423
 
399
- ### :timeout => duration or point in time
424
+ ### timeout: duration or point in time
400
425
 
401
426
  It's OK to specify a timeout when scheduling some work. After the time specified, it gets interrupted via a Rufus::Scheduler::TimeoutError.
402
427
 
403
428
  ```ruby
404
- scheduler.in '10d', :timeout => '1d' do
429
+ scheduler.in '10d', timeout: '1d' do
405
430
  begin
406
431
  # ... do something
407
432
  rescue Rufus::Scheduler::TimeoutError
@@ -422,15 +447,15 @@ In the case of an "every" job, this will be the first time (modulo the scheduler
422
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.
423
448
 
424
449
  ```ruby
425
- scheduler.every '2d', :first_at => Time.now + 10 * 3600 do
450
+ scheduler.every '2d', first_at: Time.now + 10 * 3600 do
426
451
  # ... every two days, but start in 10 hours
427
452
  end
428
453
 
429
- scheduler.every '2d', :first_in => '10h' do
454
+ scheduler.every '2d', first_in: '10h' do
430
455
  # ... every two days, but start in 10 hours
431
456
  end
432
457
 
433
- scheduler.cron '00 14 * * *', :first_in => '3d' do
458
+ scheduler.cron '00 14 * * *', first_in: '3d' do
434
459
  # ... every day at 14h00, but start after 3 * 24 hours
435
460
  end
436
461
  ```
@@ -452,12 +477,11 @@ s = Rufus::Scheduler.new
452
477
 
453
478
  n = Time.now; p [ :scheduled_at, n, n.to_f ]
454
479
 
455
- s.every '3s', :first => :now do
480
+ s.every '3s', first: :now do
456
481
  n = Time.now; p [ :in, n, n.to_f ]
457
482
  end
458
483
 
459
484
  s.join
460
-
461
485
  ```
462
486
 
463
487
  that'll output something like:
@@ -478,15 +502,15 @@ This option is for repeat jobs (cron / every) only.
478
502
  It indicates the point in time after which the job should unschedule itself.
479
503
 
480
504
  ```ruby
481
- scheduler.cron '5 23 * * *', :last_in => '10d' do
505
+ scheduler.cron '5 23 * * *', last_in: '10d' do
482
506
  # ... do something every evening at 23:05 for 10 days
483
507
  end
484
508
 
485
- scheduler.every '10m', :last_at => Time.now + 10 * 3600 do
509
+ scheduler.every '10m', last_at: Time.now + 10 * 3600 do
486
510
  # ... do something every 10 minutes for 10 hours
487
511
  end
488
512
 
489
- scheduler.every '10m', :last_in => 10 * 3600 do
513
+ scheduler.every '10m', last_in: 10 * 3600 do
490
514
  # ... do something every 10 minutes for 10 hours
491
515
  end
492
516
  ```
@@ -501,16 +525,16 @@ job.last_at = Rufus::Scheduler.parse('2029-12-12')
501
525
  # set the last bound
502
526
  ```
503
527
 
504
- ### :times => nb of times (before auto-unscheduling)
528
+ ### times: nb of times (before auto-unscheduling)
505
529
 
506
530
  One can tell how many times a repeat job (CronJob or EveryJob) is to execute before unscheduling by itself.
507
531
 
508
532
  ```ruby
509
- scheduler.every '2d', :times => 10 do
533
+ scheduler.every '2d', times: 10 do
510
534
  # ... do something every two days, but not more than 10 times
511
535
  end
512
536
 
513
- scheduler.cron '0 23 * * *', :times => 31 do
537
+ scheduler.cron '0 23 * * *', times: 31 do
514
538
  # ... do something every day at 23:00 but do it no more than 31 times
515
539
  end
516
540
  ```
@@ -518,7 +542,7 @@ end
518
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.
519
543
 
520
544
  ```ruby
521
- scheduler.cron '0 23 * * *', :times => nolimit ? nil : 10 do
545
+ scheduler.cron '0 23 * * *', times: (nolimit ? nil : 10) do
522
546
  # ...
523
547
  end
524
548
  ```
@@ -540,7 +564,7 @@ job.times = 10
540
564
 
541
565
  ## Job methods
542
566
 
543
- 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).
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).
544
568
 
545
569
  ```ruby
546
570
  require 'rufus-scheduler'
@@ -558,7 +582,7 @@ When calling a schedule method, the id (String) of the job is returned. Longer s
558
582
  end
559
583
 
560
584
  job =
561
- scheduler.in '1w', :job => true do
585
+ scheduler.in '1w', job: true do
562
586
  # ...
563
587
  end
564
588
  ```
@@ -584,7 +608,7 @@ Returns the scheduler instance itself.
584
608
  Returns the options passed at the Job creation.
585
609
 
586
610
  ```ruby
587
- job = scheduler.schedule_in('10d', :tag => 'hello') do; end
611
+ job = scheduler.schedule_in('10d', tag: 'hello') do; end
588
612
  job.opts
589
613
  # => { :tag => 'hello' }
590
614
  ```
@@ -594,7 +618,7 @@ job.opts
594
618
  Returns the original schedule.
595
619
 
596
620
  ```ruby
597
- job = scheduler.schedule_in('10d', :tag => 'hello') do; end
621
+ job = scheduler.schedule_in('10d', tag: 'hello') do; end
598
622
  job.original
599
623
  # => '10d'
600
624
  ```
@@ -641,12 +665,30 @@ job.callable
641
665
  # => #<MyHandler:0x0000000163ae88 @counter=0>
642
666
  ```
643
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
+
644
686
  ### scheduled_at
645
687
 
646
688
  Returns the Time instance when the job got created.
647
689
 
648
690
  ```ruby
649
- job = scheduler.schedule_in('10d', :tag => 'hello') do; end
691
+ job = scheduler.schedule_in('10d', tag: 'hello') do; end
650
692
  job.scheduled_at
651
693
  # => 2013-07-17 23:48:54 +0900
652
694
  ```
@@ -687,6 +729,12 @@ The job keeps track of how long its work was in the `last_work_time` attribute.
687
729
 
688
730
  The attribute `mean_work_time` contains a computed mean work time. It's recomputed after every run (if it's a repeat job).
689
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
+
690
738
  ### unschedule
691
739
 
692
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.
@@ -743,14 +791,14 @@ job = scheduler.schedule_in('10d') do; end
743
791
  job.tags
744
792
  # => []
745
793
 
746
- job = scheduler.schedule_in('10d', :tag => 'hello') do; end
794
+ job = scheduler.schedule_in('10d', tag: 'hello') do; end
747
795
  job.tags
748
796
  # => [ 'hello' ]
749
797
  ```
750
798
 
751
- ### []=, [], key? and keys
799
+ ### []=, [], key?, has_key?, keys, values, and entries
752
800
 
753
- Threads have thread-local variables. Rufus-scheduler jobs have job-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.
754
802
 
755
803
  ```ruby
756
804
  job =
@@ -765,13 +813,29 @@ sleep 3.6
765
813
  job[:counter]
766
814
  # => 3
767
815
 
768
- job.key?(:timestamp)
769
- # => true
770
- job.keys
771
- # => [ :timestamp, :counter ]
816
+ job.key?(:timestamp) # => true
817
+ job.has_key?(:timestamp) # => true
818
+ job.keys # => [ :timestamp, :counter ]
772
819
  ```
773
820
 
774
- Job-local variables are thread-safe.
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
+ ```
775
839
 
776
840
  ### call
777
841
 
@@ -912,24 +976,24 @@ Here is an example:
912
976
  scheduler.at_jobs.each(&:unschedule)
913
977
  ```
914
978
 
915
- ### Scheduler#jobs(:tag / :tags => x)
979
+ ### Scheduler#jobs(tag: / tags: x)
916
980
 
917
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.
918
982
 
919
983
  ```ruby
920
- scheduler.in '10d', :tag => 'main_process' do
984
+ scheduler.in '10d', tag: 'main_process' do
921
985
  # ...
922
986
  end
923
- scheduler.in '10d', :tags => [ 'main_process', 'side_dish' ] do
987
+ scheduler.in '10d', tags: [ 'main_process', 'side_dish' ] do
924
988
  # ...
925
989
  end
926
990
 
927
991
  # ...
928
992
 
929
- jobs = scheduler.jobs(:tag => 'main_process')
993
+ jobs = scheduler.jobs(tag: 'main_process')
930
994
  # find all the jobs with the 'main_process' tag
931
995
 
932
- jobs = scheduler.jobs(:tags => [ 'main_process', 'side_dish' ]
996
+ jobs = scheduler.jobs(tags: [ 'main_process', 'side_dish' ]
933
997
  # find all the jobs with the 'main_process' AND 'side_dish' tags
934
998
  ```
935
999
 
@@ -954,6 +1018,10 @@ Shuts down the scheduler, ceases any scheduler/triggering activity.
954
1018
 
955
1019
  Shuts down the scheduler, waits (blocks) until all the jobs cease running.
956
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
+
957
1025
  ### Scheduler#shutdown(:kill)
958
1026
 
959
1027
  Kills all the job (threads) and then shuts the scheduler down. Radical.
@@ -976,6 +1044,8 @@ Returns since the count of seconds for which the scheduler has been running.
976
1044
 
977
1045
  Lets the current thread join the scheduling thread in rufus-scheduler. The thread comes back when the scheduler gets shut down.
978
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
+
979
1049
  ### Scheduler#threads
980
1050
 
981
1051
  Returns all the threads associated with the scheduler, including the scheduler thread itself.
@@ -988,7 +1058,7 @@ Lists the work threads associated with the scheduler. The query option defaults
988
1058
  * :active : all the work threads currently running a Job
989
1059
  * :vacant : all the work threads currently not running a Job
990
1060
 
991
- Note that the main schedule thread will be returned if it is currently running a Job (ie one of those :blocking => true jobs).
1061
+ Note that the main schedule thread will be returned if it is currently running a Job (ie one of those `blocking: true` jobs).
992
1062
 
993
1063
  ### Scheduler#scheduled?(job_or_job_id)
994
1064
 
@@ -996,7 +1066,7 @@ Returns true if the arg is a currently scheduled job (see Job#scheduled?).
996
1066
 
997
1067
  ### Scheduler#occurrences(time0, time1)
998
1068
 
999
- Returns a hash ```{ job => [ t0, t1, ... ] }``` mapping jobs to their potential trigger time within the ```[ time0, time1 ]``` span.
1069
+ Returns a hash `{ job => [ t0, t1, ... ] }` mapping jobs to their potential trigger time within the `[ time0, time1 ]` span.
1000
1070
 
1001
1071
  Please note that, for interval jobs, the ```#mean_work_time``` is used, so the result is only a prediction.
1002
1072
 
@@ -1088,7 +1158,9 @@ def scheduler.on_error(job, error)
1088
1158
  end
1089
1159
  ```
1090
1160
 
1091
- ## Rufus::Scheduler #on_pre_trigger and #on_post_trigger callbacks
1161
+ ## Callbacks
1162
+
1163
+ ### Rufus::Scheduler #on_pre_trigger and #on_post_trigger callbacks
1092
1164
 
1093
1165
  One can bind callbacks before and after jobs trigger:
1094
1166
 
@@ -1112,6 +1184,21 @@ The ```trigger_time``` is the time at which the job triggers. It might be a bit
1112
1184
 
1113
1185
  Warning: these two callbacks are executed in the scheduler thread, not in the work threads (the threads where the job execution really happens).
1114
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
+
1115
1202
  ### Rufus::Scheduler#on_pre_trigger as a guard
1116
1203
 
1117
1204
  Returning ```false``` in on_pre_trigger will prevent the job from triggering. Returning anything else (nil, -1, true, ...) will let the job trigger.
@@ -1136,23 +1223,23 @@ By default, rufus-scheduler sleeps 0.300 second between every step. At each step
1136
1223
  The :frequency option lets you change that 0.300 second to something else.
1137
1224
 
1138
1225
  ```ruby
1139
- scheduler = Rufus::Scheduler.new(:frequency => 5)
1226
+ scheduler = Rufus::Scheduler.new(frequency: 5)
1140
1227
  ```
1141
1228
 
1142
1229
  It's OK to use a time string to specify the frequency.
1143
1230
 
1144
1231
  ```ruby
1145
- scheduler = Rufus::Scheduler.new(:frequency => '2h10m')
1232
+ scheduler = Rufus::Scheduler.new(frequency: '2h10m')
1146
1233
  # this scheduler will sleep 2 hours and 10 minutes between every "step"
1147
1234
  ```
1148
1235
 
1149
1236
  Use with care.
1150
1237
 
1151
- ### :lockfile => "mylockfile.txt"
1238
+ ### lockfile: "mylockfile.txt"
1152
1239
 
1153
1240
  This feature only works on OSes that support the flock (man 2 flock) call.
1154
1241
 
1155
- 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.
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.
1156
1243
 
1157
1244
  The idea is to guarantee only one scheduler (in a group of schedulers sharing the same lockfile) is running.
1158
1245
 
@@ -1181,7 +1268,7 @@ class HostLock
1181
1268
  end
1182
1269
 
1183
1270
  scheduler =
1184
- Rufus::Scheduler.new(:scheduler_lock => HostLock.new('coffee.example.com'))
1271
+ Rufus::Scheduler.new(scheduler_lock: HostLock.new('coffee.example.com'))
1185
1272
  ```
1186
1273
 
1187
1274
  By default, the scheduler_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that returns true.
@@ -1204,7 +1291,7 @@ class PingLock
1204
1291
  end
1205
1292
 
1206
1293
  scheduler =
1207
- Rufus::Scheduler.new(:trigger_lock => PingLock.new('main.example.com'))
1294
+ Rufus::Scheduler.new(trigger_lock: PingLock.new('main.example.com'))
1208
1295
  ```
1209
1296
 
1210
1297
  By default, the trigger_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that always returns true.
@@ -1218,7 +1305,7 @@ In rufus-scheduler 2.x, by default, each job triggering received its own, brand
1218
1305
  One can set this maximum value when starting the scheduler.
1219
1306
 
1220
1307
  ```ruby
1221
- scheduler = Rufus::Scheduler.new(:max_work_threads => 77)
1308
+ scheduler = Rufus::Scheduler.new(max_work_threads: 77)
1222
1309
  ```
1223
1310
 
1224
1311
  It's OK to increase the :max_work_threads of a running scheduler.
@@ -1231,7 +1318,7 @@ scheduler.max_work_threads += 10
1231
1318
  ## Rufus::Scheduler.singleton
1232
1319
 
1233
1320
  Do not want to store a reference to your rufus-scheduler instance?
1234
- Then ```Rufus::Scheduler.singleton``` can help, it returns a singleon instance of the scheduler, initialized the first time this class method is called.
1321
+ Then ```Rufus::Scheduler.singleton``` can help, it returns a singleton instance of the scheduler, initialized the first time this class method is called.
1235
1322
 
1236
1323
  ```ruby
1237
1324
  Rufus::Scheduler.singleton.every '10s' { puts "hello, world!" }
@@ -1240,8 +1327,8 @@ Rufus::Scheduler.singleton.every '10s' { puts "hello, world!" }
1240
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.
1241
1328
 
1242
1329
  ```ruby
1243
- Rufus::Scheduler.singleton(:max_work_threads => 77)
1244
- Rufus::Scheduler.singleton(:max_work_threads => 277) # no effect
1330
+ Rufus::Scheduler.singleton(max_work_threads: 77)
1331
+ Rufus::Scheduler.singleton(max_work_threads: 277) # no effect
1245
1332
  ```
1246
1333
 
1247
1334
  The ```.s``` is a shortcut for ```.singleton```.
@@ -1290,7 +1377,7 @@ class ZookeptScheduler < Rufus::Scheduler
1290
1377
  end
1291
1378
  ```
1292
1379
 
1293
- This uses a [zookeeper](http://zookeeper.apache.org/) to make sure only one scheduler in a group of distributed schedulers runs.
1380
+ This uses a [zookeeper](https://zookeeper.apache.org/) to make sure only one scheduler in a group of distributed schedulers runs.
1294
1381
 
1295
1382
  The methods #lock and #unlock are overridden and #confirm_lock is provided,
1296
1383
  to make sure that the lock is still valid.
@@ -1314,6 +1401,8 @@ Warning: you may think you're heading towards "high availability" by using a tri
1314
1401
 
1315
1402
  ## parsing cronlines and time strings
1316
1403
 
1404
+ (Please note that [fugit](https://github.com/floraison/fugit) does the heavy-lifting parsing work for rufus-scheduler).
1405
+
1317
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).
1318
1407
 
1319
1408
  ```ruby
@@ -1356,7 +1445,7 @@ Rufus::Scheduler.to_duration_hash(60)
1356
1445
  Rufus::Scheduler.to_duration_hash(62.127)
1357
1446
  # => { :m => 1, :s => 2, :ms => 127 }
1358
1447
 
1359
- Rufus::Scheduler.to_duration_hash(62.127, :drop_seconds => true)
1448
+ Rufus::Scheduler.to_duration_hash(62.127, drop_seconds: true)
1360
1449
  # => { :m => 1 }
1361
1450
  ```
1362
1451
 
@@ -1539,7 +1628,7 @@ class ScheController < ApplicationController
1539
1628
  Rails.logger.info "time flies, it's now #{Time.now}"
1540
1629
  end
1541
1630
 
1542
- render :text => "scheduled job #{job_id}"
1631
+ render text: "scheduled job #{job_id}"
1543
1632
  end
1544
1633
  end
1545
1634
  ```
@@ -1550,9 +1639,9 @@ The rufus-scheduler singleton is instantiated in the ```config/initializers/sche
1550
1639
 
1551
1640
  ### avoid scheduling when running the Ruby on Rails console
1552
1641
 
1553
- (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))
1554
1643
 
1555
- If you don't want rufus-scheduler to kick in when running the Ruby on Rails console or invoking a rake task, you can wrap your initializer in a conditional:
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:
1556
1645
 
1557
1646
  ```ruby
1558
1647
  #
@@ -1560,23 +1649,25 @@ If you don't want rufus-scheduler to kick in when running the Ruby on Rails cons
1560
1649
 
1561
1650
  require 'rufus-scheduler'
1562
1651
 
1563
- s = Rufus::Scheduler.singleton
1564
-
1565
-
1566
- unless defined?(Rails::Console) || File.split($0).last == 'rake'
1652
+ return if defined?(Rails::Console) || Rails.env.test? || File.split($PROGRAM_NAME).last == 'rake'
1653
+ #
1654
+ # do not schedule when Rails is run from its console, for a test/spec, or
1655
+ # from a Rake task
1567
1656
 
1568
- # only schedule when not running from the Ruby on Rails console
1569
- # or from a rake task
1657
+ # return if $PROGRAM_NAME.include?('spring')
1658
+ #
1659
+ # see https://github.com/jmettraux/rufus-scheduler/issues/186
1570
1660
 
1571
- s.every '1m' do
1661
+ s = Rufus::Scheduler.singleton
1572
1662
 
1573
- Rails.logger.info "hello, it's #{Time.now}"
1574
- Rails.logger.flush
1575
- end
1663
+ s.every '1m' do
1664
+ Rails.logger.info "hello, it's #{Time.now}"
1665
+ Rails.logger.flush
1576
1666
  end
1577
1667
  ```
1578
1668
 
1579
- It should work for Ruby on Rails 3 and 4.
1669
+ (Beware later version of Rails where Spring takes care pre-running the initializers. Running `spring stop` or disabling Spring might be necessary in some cases to see changes to initializers being taken into account.)
1670
+
1580
1671
 
1581
1672
  ### rails server -d
1582
1673
 
@@ -1588,11 +1679,14 @@ I avoid running `-d` in development mode and bother about daemonizing only for p
1588
1679
 
1589
1680
  These are two well crafted articles on process daemonization, please read them:
1590
1681
 
1591
- * http://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
1592
- * http://www.mikeperham.com/2014/07/07/use-runit/
1682
+ * https://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
1683
+ * https://www.mikeperham.com/2014/07/07/use-runit/
1593
1684
 
1594
1685
  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).
1595
1686
 
1687
+ ### executor / reloader
1688
+
1689
+ You might benefit from wraping your scheduled code in the executor or reloader. Read more here: https://guides.rubyonrails.org/threading_and_code_execution.html
1596
1690
 
1597
1691
  ## support
1598
1692