fugit 1.1.8 → 1.1.9

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
  SHA1:
3
- metadata.gz: 58d147427cf9a05edc023aff03f2a66327630136
4
- data.tar.gz: 4ec39bf97a9ead1ada6b7ae28ce1584bb481d76a
3
+ metadata.gz: 35836e95c82a113fe2e5222a02522ab2bf36f1b0
4
+ data.tar.gz: 0fb6db1cb77893af937354da715b2eb8b14403f5
5
5
  SHA512:
6
- metadata.gz: 7ebf332f1ef63e6d4ab8a7d948a896ed0d901a53cffb870206fb7a8109c29fd0510e0809e332c0202429896e5c0f74ef486bcab0436100548ebc53d0299a0487
7
- data.tar.gz: e390316cf035e0a4228d9e8078c7e417dcb093a98b85cffe0d4f379d08709af8faae00d017e4b9a00a38a9d5eafae33e1206a47ea3e17dafd482ff3aa517d290
6
+ metadata.gz: 7de61477e96c9612542641787346fb154394d8388eccccaeb1be257cb57410abe4e23d1377148539d92852674df3c58d0a44c9cc4816c50cd157515f185d59da
7
+ data.tar.gz: c1f23c4a8395ddc29a85415300608fbc45d5900cbb42c502fd51f02f7f8c5f6fe945fe9b010349e9bde6fc1df6f3ec105a977c8705722820be41c65b47656ff7
@@ -2,6 +2,14 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 1.1.9 released 2019-03-26
6
+
7
+ * Fix cron `"0 9 29 feb *"` endless loop, gh-18
8
+ * Fix cron endless loop when #previous_time(t) and t matches, gh-15
9
+ * Simplify Cron #next_time / #previous_time breaker system, gh-15
10
+ Thanks @godfat and @conet
11
+
12
+
5
13
  ## fugit 1.1.8 released 2019-01-17
6
14
 
7
15
  * Ensure Cron#next_time happens in cron's time zone, gh-12
data/CREDITS.md CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  # fugit credits
3
3
 
4
+ * Cristian Oneț https://githbu.com/conet #previous_time vs 1/-1 endless loop #15
4
5
  * Wenhui Wang https://github.com/w11th #next_time vs Chronic+ActiveSupport #11
5
6
  * Lin-Jen Shin https://github.com/godfat #next_time untamed loop, #13
6
7
  * Nils Mueller https://github.com/Tolsto missing Olson timezone names, #9
@@ -17,5 +18,5 @@
17
18
  As fugit originates in rufus-scheduler, many thanks to all the
18
19
  rufus-scheduler contributors and people who gave feedback.
19
20
 
20
- https://github.com/jmettraux/rufus-scheduler/blob/master/CREDITS.txt
21
+ https://github.com/jmettraux/rufus-scheduler/blob/master/CREDITS.md
21
22
 
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  [![Build Status](https://secure.travis-ci.org/floraison/fugit.svg)](http://travis-ci.org/floraison/fugit)
5
5
  [![Gem Version](https://badge.fury.io/rb/fugit.svg)](http://badge.fury.io/rb/fugit)
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
  Time tools for [flor](https://github.com/floraison/flor) and the floraison group.
8
9
 
@@ -34,9 +35,9 @@ The intersection of those two projects is where fugit is born:
34
35
  * [sideqik-cron](https://github.com/ondrejbartas/sidekiq-cron) - recent versions of Sideqik-Cron use fugit to parse cron strings
35
36
  * [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) -
36
37
  * [flor](https://github.com/floraison/flor) - used in the [cron](https://github.com/floraison/flor/blob/master/doc/procedures/cron.md) procedure
38
+ * [que-scheduler](https://github.com/hlascelles/que-scheduler) - a reliable job scheduler for [que](https://github.com/chanks/que)
37
39
  * ...
38
40
 
39
-
40
41
  ## `Fugit.parse(s)`
41
42
 
42
43
  The simplest way to use fugit is via `Fugit.parse(s)`.
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Fugit
3
3
 
4
- VERSION = '1.1.8'
4
+ VERSION = '1.1.9'
5
5
  end
6
6
 
7
7
  require 'time'
@@ -64,7 +64,8 @@ module Fugit
64
64
 
65
65
  class TimeCursor
66
66
 
67
- def initialize(t)
67
+ def initialize(cron, t)
68
+ @cron = cron
68
69
  @t = t.is_a?(TimeCursor) ? t.time : t
69
70
  @t.seconds = @t.seconds.to_i
70
71
  end
@@ -88,28 +89,49 @@ module Fugit
88
89
  @t = ::EtOrbi.make(y, m, @t.zone)
89
90
  self
90
91
  end
91
- def inc_day; inc((24 - @t.hour) * 3600 - @t.min * 60 - @t.sec); end
92
- def inc_hour; inc((60 - @t.min) * 60 - @t.sec); end
93
- def inc_min; inc(60 - @t.sec); end
94
92
 
95
- def inc_sec(seconds)
96
- if sec = seconds.find { |s| s > @t.sec }
93
+ def inc_day
94
+ inc((24 - @t.hour) * 3600 - @t.min * 60 - @t.sec)
95
+ end
96
+ def inc_hour
97
+ inc((60 - @t.min) * 60 - @t.sec)
98
+ end
99
+ def inc_min
100
+ inc(60 - @t.sec)
101
+ end
102
+
103
+ def inc_sec
104
+ if sec = @cron.seconds.find { |s| s > @t.sec }
97
105
  inc(sec - @t.sec)
98
106
  else
99
- inc(60 - @t.sec + seconds.first)
107
+ inc(60 - @t.sec + @cron.seconds.first)
100
108
  end
101
109
  end
102
110
 
103
111
  def dec_month
104
- dec(@t.day * 24 * 3600 + @t.hour * 3600 + @t.min * 60 + @t.sec + 1)
112
+
113
+ #dec(@t.day * 24 * 3600 + @t.hour * 3600 + @t.min * 60 + @t.sec + 1)
114
+ #
115
+ # gh-18, so that '0 9 29 feb *' doesn't get skipped (over and over)
116
+ #
117
+ dec(@t.day * 24 * 3600 + 1)
118
+ end
119
+
120
+ def dec_day
121
+ dec(@t.hour * 3600 + @t.min * 60 + @t.sec + 1)
122
+ end
123
+ def dec_hour
124
+ dec(@t.min * 60 + @t.sec + 1)
125
+ end
126
+ def dec_min
127
+ dec(@t.sec + 1)
105
128
  end
106
- def dec_day; dec(@t.hour * 3600 + @t.min * 60 + @t.sec + 1); end
107
- def dec_hour; dec(@t.min * 60 + @t.sec + 1); end
108
- def dec_min; dec(@t.sec + 1); end
109
129
 
110
- def dec_sec(seconds)
111
- target = seconds.reverse.find { |s| s < @t.sec } || seconds.last
112
- inc(target - @t.sec)
130
+ def dec_sec
131
+ target =
132
+ @cron.seconds.reverse.find { |s| s < @t.sec } ||
133
+ @cron.seconds.last
134
+ inc(target - @t.sec - (@t.sec > target ? 0 : 60))
113
135
  end
114
136
  end
115
137
 
@@ -140,7 +162,7 @@ module Fugit
140
162
 
141
163
  return true if @monthdays.nil?
142
164
 
143
- last = (TimeCursor.new(nt).inc_month.time - 24 * 3600).day + 1
165
+ last = (TimeCursor.new(self, nt).inc_month.time - 24 * 3600).day + 1
144
166
 
145
167
  @monthdays
146
168
  .collect { |d| d < 1 ? last + d : d }
@@ -166,47 +188,43 @@ module Fugit
166
188
  hour_match?(t) && min_match?(t) && sec_match?(t)
167
189
  end
168
190
 
169
- BREAKER_S = 41 * (365 + 1) * 24 * 3600
170
- # 41 years and a few days... there wont'be a next or a previous time
191
+ MAX_ITERATION_COUNT = 2048
192
+ #
193
+ # See gh-15 and tst/iteration_count.rb
194
+ #
195
+ # Initially set to 1024 after seeing the worst case for #next_time
196
+ # at 167 iterations, I placed it at 2048 after experimenting with
197
+ # gh-18 and noticing some > 1024 for some experiments. 2048 should
198
+ # be ok.
171
199
 
172
200
  def next_time(from=::EtOrbi::EoTime.now)
173
201
 
174
202
  from = ::EtOrbi.make_time(from)
175
- sfrom = from.strftime('%F/%T')
203
+ sfrom = from.strftime('%F|%T')
176
204
  ifrom = from.to_i
177
205
 
178
- t = TimeCursor.new(from.translate(@timezone))
206
+ i = 0
207
+ t = TimeCursor.new(self, from.translate(@timezone))
179
208
  #
180
209
  # the translation occurs in the timezone of
181
210
  # this Fugit::Cron instance
182
211
 
183
- ti = 0
184
- stalling = false
185
-
186
212
  loop do
187
213
 
188
- ti1 = t.to_i
189
-
190
- fail RuntimeError.new(
191
- "loop stalled for #{@original.inspect} #next_time, breaking"
192
- ) if stalling && ti == ti1
193
-
194
- stalling = (ti == ti1)
195
- ti = ti1
196
-
197
214
  fail RuntimeError.new(
198
- "too many loops for #{@original.inspect} #next_time, breaking"
199
- ) if (ti - ifrom).abs > BREAKER_S
215
+ "too many loops for #{@original.inspect} #next_time, breaking, " +
216
+ "please fill an issue at https://git.io/fjJC9"
217
+ ) if (i += 1) > MAX_ITERATION_COUNT
200
218
 
201
- (ifrom == ti) && (t.inc(1); next)
219
+ (ifrom == t.to_i) && (t.inc(1); next)
202
220
  month_match?(t) || (t.inc_month; next)
203
221
  day_match?(t) || (t.inc_day; next)
204
222
  hour_match?(t) || (t.inc_hour; next)
205
223
  min_match?(t) || (t.inc_min; next)
206
- sec_match?(t) || (t.inc_sec(@seconds); next)
224
+ sec_match?(t) || (t.inc_sec; next)
207
225
 
208
- st = t.time.strftime('%F/%T')
209
- (from, sfrom, ifrom = t.time, st, t.time.to_i; next) if st == sfrom
226
+ st = t.time.strftime('%F|%T')
227
+ (from, sfrom, ifrom = t.time, st, t.to_i; next) if st == sfrom
210
228
  #
211
229
  # when transitioning out of DST, this prevents #next_time from
212
230
  # yielding the same literal time twice in a row, see gh-6
@@ -223,33 +241,22 @@ module Fugit
223
241
  def previous_time(from=::EtOrbi::EoTime.now)
224
242
 
225
243
  from = ::EtOrbi.make_time(from)
226
- ti = 0
227
- ifrom = from.to_i
228
244
 
229
- t = TimeCursor.new(from.translate(@timezone))
230
- stalling = false
245
+ i = 0
246
+ t = TimeCursor.new(self, (from - 1).translate(@timezone))
231
247
 
232
248
  loop do
233
249
 
234
- ti1 = t.to_i
235
-
236
- fail RuntimeError.new(
237
- "loop stalled for #{@original.inspect} #previous_time, breaking"
238
- ) if stalling && ti == ti1
239
-
240
- stalling = (ti == ti1)
241
- ti = ti1
242
-
243
250
  fail RuntimeError.new(
244
- "too many loops for #{@original.inspect} #previous_time, breaking"
245
- ) if (ifrom - ti).abs > BREAKER_S
251
+ "too many loops for #{@original.inspect} #previous_time, breaking, " +
252
+ "please fill an issue at https://git.io/fjJCQ"
253
+ ) if (i += 1) > MAX_ITERATION_COUNT
246
254
 
247
- (ifrom == ti) && (t.inc(-1); next)
248
255
  month_match?(t) || (t.dec_month; next)
249
256
  day_match?(t) || (t.dec_day; next)
250
257
  hour_match?(t) || (t.dec_hour; next)
251
258
  min_match?(t) || (t.dec_min; next)
252
- sec_match?(t) || (t.dec_sec(@seconds); next)
259
+ sec_match?(t) || (t.dec_sec; next)
253
260
  break
254
261
  end
255
262
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fugit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-17 00:00:00.000000000 Z
11
+ date: 2019-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raabro