rufus-scheduler 3.8.1 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fec88a5f600474172a07002ec7a17c2b35cd9aeffff3e2cfe9865e49e0c9a6d7
4
- data.tar.gz: ca607aef24a501fd1a23370e230c6481fe8624c6111c79b11f7f59fc5edc5884
3
+ metadata.gz: ec5b405be33c70ef390f2d8c47be112c7cf05c32eda58a0a764bbf42fae1b5d6
4
+ data.tar.gz: c03f4dc830c7041a530d899d69d91f7409ba481bbd12241152543b0eae20fc23
5
5
  SHA512:
6
- metadata.gz: 0e2535642cb251105341e3d70998500f86370d41b13a6841698e15bc729d5d94ec420cfa4dc4549794ff53b82e442ae61962a61f10751a10c303f21a991d4cfc
7
- data.tar.gz: bdfe0713a8b5bbec83403dbc1232f5bd310579707fd7b838a224367bc4cdd34752defc47f9cc1bb0686267c3a4b49114490866d6b8dcde22ce6ec3c52479ea90
6
+ metadata.gz: e5d992e7ad0a23530320731348c3c890b90d0184851d7faf807a36e4c6dd5d879579a478478055beab569e14603f129a7ad15022f2bf6b297a3e9f27cb31fb4c
7
+ data.tar.gz: 85be36f54b76add7704907a3a7d43339a392d49fc05e03b62dc28e20a88eeb03cd132f64e1f3a1378f2e6e3128d57fb7fa4fe6f6ccd89fdd8b1d24fe93312583
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ### rufus-scheduler 3.9.0 - released 2023-06-02
6
+
7
+ * Add note about Chronic and "Wed at 2pm", gh-340
8
+ * Let AtJob and InJob accept discard_past:
9
+ * Enforce discard_past for At and In jobs, gh-339
10
+
11
+
12
+ ### rufus-scheduler 3.8.2 - released 2022-07-12
13
+
14
+ * Prevent error in shutdown when @thread is current Thread, gh-337
15
+ * Rescue errors on the scheduling thread, gh-335
16
+
17
+
5
18
  ### rufus-scheduler 3.8.1 - released 2022-01-11
6
19
 
7
20
  * Suppress warning about @resume_discard_past
data/CREDITS.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## Contributors
6
6
 
7
+ * Bence Monus https://github.com/cromega gh-337 on_error and friends
8
+ * Talia Wong https://github.com/blowfishpro gh-335 on_error and friends
9
+ * Konstantin https://github.com/fa11enangel gh-334 nodejitsu link
10
+ * Olle Jonsson https://github.com/olleolleolle gh-333
7
11
  * Sol Ackerman https://github.com/solarckerman gh-332
8
12
  * John Bachir https://github.com/jjb gh-310 gh-327
9
13
  * Daniel Berger https://github.com/djberg96 gh-300
data/LICENSE.txt CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright (c) 2005-2022, John Mettraux, jmettraux@gmail.com
2
+ Copyright (c) 2005-2023, 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
@@ -1,8 +1,8 @@
1
1
 
2
- NAME = \
3
- $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name")
4
- VERSION = \
5
- $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version")
2
+ NAME != \
3
+ ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name"
4
+ VERSION != \
5
+ ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version"
6
6
 
7
7
  count_lines:
8
8
  find lib -name "*.rb" | xargs cat | ruby -e "p STDIN.readlines.count { |l| l = l.strip; l[0, 1] != '#' && l != '' }"
data/README.md CHANGED
@@ -3,7 +3,6 @@
3
3
 
4
4
  [![tests](https://github.com/jmettraux/rufus-scheduler/workflows/test/badge.svg)](https://github.com/jmettraux/rufus-scheduler/actions)
5
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)
7
6
 
8
7
  Job scheduler for Ruby (at, cron, in and every jobs).
9
8
 
@@ -106,7 +105,7 @@ I'll drive you right to the [tracks](#so-rails).
106
105
  * Rufus::Scheduler::TimeOutError renamed to Rufus::Scheduler::TimeoutError
107
106
  * 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"
108
107
  * 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.
108
+ * "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).
110
109
  * Introduction of Scheduler #on_pre_trigger and #on_post_trigger callback points
111
110
 
112
111
 
@@ -120,12 +119,6 @@ Go read [how to report bugs effectively](https://www.chiark.greenend.org.uk/~sgt
120
119
 
121
120
  Update: [help_help.md](https://gist.github.com/jmettraux/310fed75f568fd731814) might help help you.
122
121
 
123
- ### on Gitter
124
-
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.
126
-
127
- Please be courteous.
128
-
129
122
  ### issues
130
123
 
131
124
  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.
@@ -133,7 +126,7 @@ Yes, issues can be reported in [rufus-scheduler issues](https://github.com/jmett
133
126
  ### faq
134
127
 
135
128
  * [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)
129
+ * [I want a refund](https://web.archive.org/web/20160425034214/http://blog.nodejitsu.com/getting-refunds-on-open-source-projects/)
137
130
  * [Passenger and rufus-scheduler](https://stackoverflow.com/questions/18108719/debugging-rufus-scheduler/18156180#18156180)
138
131
  * [Passenger and rufus-scheduler (2)](https://stackoverflow.com/questions/21861387/rufus-cron-job-not-working-in-apache-passenger#answer-21868555)
139
132
  * [Passenger in-depth spawn methods](https://www.phusionpassenger.com/library/indepth/ruby/spawn_methods/)
@@ -198,7 +191,34 @@ Interval jobs trigger, execute and then trigger again after the interval elapsed
198
191
 
199
192
  Cron jobs are based on the venerable cron utility (```man 5 crontab```). They trigger following a pattern given in (almost) the same language cron uses.
200
193
 
201
- ####
194
+ ### Chronic and "Wed at 2pm"
195
+
196
+ By default, rufus-scheduler relies on Ruby to parse strings like "Wed at 2pm". But most of the time, when calling this on Thursday, the day before is "invoked". Relying on [Chronic](https://github.com/mojombo/chronic) might solve the issue.
197
+
198
+ Compare
199
+
200
+ ```ruby
201
+ require 'rufus-scheduler'
202
+
203
+ scheduler = Rufus::Scheduler.new
204
+
205
+ scheduler.at('Wed at 2pm') do
206
+ # ... might point in the past and thus get triggered immediately
207
+ end
208
+ ```
209
+
210
+ with
211
+
212
+ ```ruby
213
+ require 'chronic'
214
+ require 'rufus-scheduler'
215
+
216
+ scheduler = Rufus::Scheduler.new
217
+
218
+ scheduler.at('Wed at 2pm') do
219
+ # ... will point to a time in the future and trigger appropriately
220
+ end
221
+ ```
202
222
 
203
223
  ### #schedule_x vs #x
204
224
 
@@ -561,6 +581,43 @@ job.times = 10
561
581
  # 10 days and it will be over
562
582
  ```
563
583
 
584
+ ### discard_past: false/true/:fail
585
+
586
+ `in` and `at` accept a `discard_past:` option since rufus-scheduler 3.9.0:
587
+
588
+ ```ruby
589
+ require 'rufus-scheduler'
590
+
591
+ scheduler = Rufus::Scheduler.new
592
+
593
+ scheduler.in(-3600, discard_past: true) {}
594
+ # the job will never get scheduled
595
+
596
+ scheduler.in(-3600, discard_past: false) {}
597
+ # the job will trigger immediately
598
+
599
+ scheduler.in(-3600, discard_past: :fail) {}
600
+ # will raise an error...
601
+ ```
602
+
603
+ Please note that `discard_past` can be set at the scheduler level:
604
+
605
+ ```ruby
606
+ require 'rufus-scheduler'
607
+
608
+ s0 = Rufus::Scheduler.new(discard_past: true) # default
609
+
610
+ s1 = Rufus::Scheduler.new(discard_past: false)
611
+ # or
612
+ s1 = Rufus::Scheduler.new
613
+ s1.discard_past = false
614
+
615
+ s2 = Rufus::Scheduler.new(discard_past: :fail)
616
+ # or
617
+ s2 = Rufus::Scheduler.new
618
+ s2.discard_past = :fail
619
+ ```
620
+
564
621
 
565
622
  ## Job methods
566
623
 
@@ -860,7 +917,11 @@ require 'rufus-scheduler'
860
917
  s = Rufus::Scheduler.new
861
918
 
862
919
  def s.on_error(job, err)
863
- p [ 'error in scheduled job', job.class, job.original, err.message ]
920
+ if job
921
+ p [ 'error in scheduled job', job.class, job.original, err.message ]
922
+ else
923
+ p [ 'error while scheduling', err.message ]
924
+ end
864
925
  rescue
865
926
  p $!
866
927
  end
@@ -67,6 +67,8 @@ class Rufus::Scheduler::Job
67
67
  @unscheduled_at = nil
68
68
  @last_time = nil
69
69
 
70
+ @discard_past = opts[:discard_past]
71
+
70
72
  @locals = opts[:locals] || opts[:l] || {}
71
73
  @local_mutex = Mutex.new
72
74
 
@@ -74,9 +76,7 @@ class Rufus::Scheduler::Job
74
76
  @name = opts[:name] || opts[:n]
75
77
 
76
78
  fail(
77
- ArgumentError,
78
- 'missing block or callable to schedule',
79
- caller[2..-1]
79
+ ArgumentError, 'missing block or callable to schedule', caller[2..-1]
80
80
  ) unless @callable
81
81
 
82
82
  @tags = Array(opts[:tag] || opts[:tags]).collect { |t| t.to_s }
@@ -103,6 +103,14 @@ class Rufus::Scheduler::Job
103
103
  end
104
104
  alias location source_location
105
105
 
106
+ # Returns true if the job is scheduled in the past.
107
+ # Used for OneTimeJob when discard_past == true
108
+ #
109
+ def past?
110
+
111
+ false # by default
112
+ end
113
+
106
114
  # Will fail with an ArgumentError if the job frequency is higher than
107
115
  # the scheduler frequency.
108
116
  #
@@ -365,5 +373,16 @@ class Rufus::Scheduler::Job
365
373
 
366
374
  @scheduler.work_queue << [ self, time ]
367
375
  end
376
+
377
+ # Scheduler level < Job level < this resume()'s level
378
+ #
379
+ def discard_past?
380
+
381
+ dp = @scheduler.discard_past
382
+ dp = @discard_past if @discard_past != nil
383
+ dp = @resume_discard_past if @resume_discard_past != nil
384
+
385
+ dp
386
+ end
368
387
  end
369
388
 
@@ -8,6 +8,14 @@ class Rufus::Scheduler::OneTimeJob < Rufus::Scheduler::Job
8
8
  (time >= time0 && time <= time1) ? [ time ] : []
9
9
  end
10
10
 
11
+ # Used when discard_past? is set to true or :fail at scheduler or job level...
12
+ #
13
+ def past?
14
+
15
+ @next_time &&
16
+ @next_time < Time.now - @scheduler.frequency
17
+ end
18
+
11
19
  protected
12
20
 
13
21
  def determine_id
@@ -20,7 +28,7 @@ class Rufus::Scheduler::OneTimeJob < Rufus::Scheduler::Job
20
28
  ].map(&:to_s).join('_')
21
29
  end
22
30
 
23
- # There is no next_time for one time jobs, hence the false.
31
+ # There is no "next time" for one time jobs, hence the false.
24
32
  #
25
33
  def set_next_time(trigger_time, is_post=false, now=nil)
26
34
 
@@ -93,7 +93,6 @@ class Rufus::Scheduler::RepeatJob < Rufus::Scheduler::Job
93
93
  def resume(opts={})
94
94
 
95
95
  @resume_discard_past = opts[:discard_past]
96
- #p [ :@resume_discard_past, @resume_discard_past ]
97
96
  @paused_at = nil
98
97
  end
99
98
 
@@ -145,17 +144,6 @@ class Rufus::Scheduler::RepeatJob < Rufus::Scheduler::Job
145
144
  a << next_time_from(a.last)
146
145
  a }
147
146
  end
148
-
149
- protected
150
-
151
- def discard_past?
152
-
153
- dp = @scheduler.discard_past
154
- dp = @discard_past if @discard_past != nil
155
- dp = @resume_discard_past if @resume_discard_past != nil
156
-
157
- dp
158
- end
159
147
  end
160
148
 
161
149
  #
@@ -180,7 +168,6 @@ class Rufus::Scheduler::EveryJob < Rufus::Scheduler::EvInJob
180
168
  super(scheduler, duration, opts, block)
181
169
 
182
170
  @frequency = Rufus::Scheduler.parse_in(@original)
183
- @discard_past = opts[:discard_past]
184
171
 
185
172
  fail ArgumentError.new(
186
173
  "cannot schedule #{self.class} with a frequency " +
@@ -9,7 +9,7 @@ module Rufus; end
9
9
 
10
10
  class Rufus::Scheduler
11
11
 
12
- VERSION = '3.8.1'
12
+ VERSION = '3.9.0'
13
13
 
14
14
  EoTime = ::EtOrbi::EoTime
15
15
 
@@ -443,10 +443,14 @@ class Rufus::Scheduler
443
443
  ms = {}; mutexes.each { |k, v| ms[k] = v.locked? }
444
444
 
445
445
  stderr.puts("{ #{pre} rufus-scheduler intercepted an error:")
446
- stderr.puts(" #{pre} job:")
447
- stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}")
448
- stderr.puts(" #{pre} #{job.source_location.inspect}")
449
- # TODO: eventually use a Job#detail or something like that
446
+ if job
447
+ stderr.puts(" #{pre} job:")
448
+ stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}")
449
+ stderr.puts(" #{pre} #{job.source_location.inspect}")
450
+ # TODO: eventually use a Job#detail or something like that
451
+ else
452
+ stderr.puts(" #{pre} job: (error did not occur in a job)")
453
+ end
450
454
  stderr.puts(" #{pre} error:")
451
455
  stderr.puts(" #{pre} #{err.object_id}")
452
456
  stderr.puts(" #{pre} #{err.class}")
@@ -530,7 +534,7 @@ class Rufus::Scheduler
530
534
 
531
535
  unlock
532
536
 
533
- @thread.join
537
+ @thread.join unless @thread == Thread.current
534
538
  end
535
539
  alias stop shutdown
536
540
 
@@ -630,12 +634,20 @@ class Rufus::Scheduler
630
634
  Thread.new do
631
635
 
632
636
  while @started_at do
637
+ begin
638
+
639
+ unschedule_jobs
640
+ trigger_jobs unless @paused_at
641
+ timeout_jobs
633
642
 
634
- unschedule_jobs
635
- trigger_jobs unless @paused_at
636
- timeout_jobs
643
+ sleep(@frequency)
637
644
 
638
- sleep(@frequency)
645
+ rescue => err
646
+ #
647
+ # for `blocking: true` jobs mostly
648
+ #
649
+ on_error(nil, err)
650
+ end
639
651
  end
640
652
 
641
653
  rejoin
@@ -710,6 +722,14 @@ class Rufus::Scheduler
710
722
  end
711
723
 
712
724
  job = job_class.new(self, t, opts, block || callable)
725
+
726
+ if job.past? && (d = job.send(:discard_past?))
727
+ fail ArgumentError.new(
728
+ "scheduling in the past and discard_past set to :fail"
729
+ ) if d == :fail
730
+ return
731
+ end
732
+
713
733
  job.check_frequency
714
734
 
715
735
  @jobs.push(job)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufus-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.8.1
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-11 00:00:00.000000000 Z
11
+ date: 2023-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fugit
@@ -88,7 +88,7 @@ metadata:
88
88
  bug_tracker_uri: https://github.com/jmettraux/rufus-scheduler/issues
89
89
  homepage_uri: https://github.com/jmettraux/rufus-scheduler
90
90
  source_code_uri: https://github.com/jmettraux/rufus-scheduler
91
- post_install_message:
91
+ post_install_message:
92
92
  rdoc_options: []
93
93
  require_paths:
94
94
  - lib
@@ -103,8 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.0.3
107
- signing_key:
106
+ rubygems_version: 3.2.33
107
+ signing_key:
108
108
  specification_version: 4
109
109
  summary: job scheduler for Ruby (at, cron, in and every jobs)
110
110
  test_files: []