fugit 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fugit might be problematic. Click here for more details.

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