timers 4.1.2 → 4.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/timers/events.rb +105 -105
- data/lib/timers/group.rb +125 -119
- data/lib/timers/interval.rb +41 -0
- data/lib/timers/priority_heap.rb +146 -0
- data/lib/timers/timer.rb +135 -125
- data/lib/timers/version.rb +6 -1
- data/lib/timers/wait.rb +48 -42
- data/lib/timers.rb +18 -3
- data/license.md +48 -0
- data/{README.md → readme.md} +29 -32
- data.tar.gz.sig +0 -0
- metadata +119 -46
- metadata.gz.sig +0 -0
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -17
- data/.rspec +0 -6
- data/.rubocop.yml +0 -28
- data/.ruby-version +0 -1
- data/.travis.yml +0 -21
- data/AUTHORS.md +0 -15
- data/CHANGES.md +0 -62
- data/Gemfile +0 -19
- data/LICENSE +0 -23
- data/Rakefile +0 -10
- data/spec/spec_helper.rb +0 -21
- data/spec/timers/cancel_spec.rb +0 -45
- data/spec/timers/events_spec.rb +0 -56
- data/spec/timers/every_spec.rb +0 -33
- data/spec/timers/group_spec.rb +0 -255
- data/spec/timers/performance_spec.rb +0 -96
- data/spec/timers/strict_spec.rb +0 -36
- data/spec/timers/wait_spec.rb +0 -30
- data/timers.gemspec +0 -26
data/spec/timers/group_spec.rb
DELETED
@@ -1,255 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Timers::Group do
|
4
|
-
describe "#wait" do
|
5
|
-
it "calls the wait block with nil" do
|
6
|
-
called = false
|
7
|
-
|
8
|
-
subject.wait do |interval|
|
9
|
-
expect(interval).to be_nil
|
10
|
-
called = true
|
11
|
-
end
|
12
|
-
|
13
|
-
expect(called).to be true
|
14
|
-
end
|
15
|
-
|
16
|
-
it "calls the wait block with an interval" do
|
17
|
-
called = false
|
18
|
-
fired = false
|
19
|
-
|
20
|
-
subject.after(0.1) { fired = true }
|
21
|
-
|
22
|
-
subject.wait do |interval|
|
23
|
-
expect(interval).to be_within(TIMER_QUANTUM).of(0.1)
|
24
|
-
called = true
|
25
|
-
sleep 0.2
|
26
|
-
end
|
27
|
-
|
28
|
-
expect(called).to be true
|
29
|
-
expect(fired).to be true
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it "sleeps until the next timer" do
|
34
|
-
interval = TIMER_QUANTUM * 2
|
35
|
-
started_at = Time.now
|
36
|
-
|
37
|
-
fired = false
|
38
|
-
subject.after(interval) { fired = true }
|
39
|
-
subject.wait
|
40
|
-
|
41
|
-
expect(fired).to be true
|
42
|
-
expect(Time.now - started_at).to be_within(TIMER_QUANTUM).of interval
|
43
|
-
end
|
44
|
-
|
45
|
-
it "fires instantly when next timer is in the past" do
|
46
|
-
fired = false
|
47
|
-
subject.after(TIMER_QUANTUM) { fired = true }
|
48
|
-
sleep(TIMER_QUANTUM * 2)
|
49
|
-
subject.wait
|
50
|
-
|
51
|
-
expect(fired).to be true
|
52
|
-
end
|
53
|
-
|
54
|
-
it "calculates the interval until the next timer should fire" do
|
55
|
-
interval = 0.1
|
56
|
-
|
57
|
-
subject.after(interval)
|
58
|
-
expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of interval
|
59
|
-
|
60
|
-
sleep(interval)
|
61
|
-
expect(subject.wait_interval).to be <= 0
|
62
|
-
end
|
63
|
-
|
64
|
-
it "fires timers in the correct order" do
|
65
|
-
result = []
|
66
|
-
|
67
|
-
subject.after(TIMER_QUANTUM * 2) { result << :two }
|
68
|
-
subject.after(TIMER_QUANTUM * 3) { result << :three }
|
69
|
-
subject.after(TIMER_QUANTUM * 1) { result << :one }
|
70
|
-
|
71
|
-
sleep TIMER_QUANTUM * 4
|
72
|
-
subject.fire
|
73
|
-
|
74
|
-
expect(result).to eq [:one, :two, :three]
|
75
|
-
end
|
76
|
-
|
77
|
-
it "raises TypeError if given an invalid time" do
|
78
|
-
expect do
|
79
|
-
subject.after(nil) { nil }
|
80
|
-
end.to raise_exception(TypeError)
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "recurring timers" do
|
84
|
-
it "continues to fire the timers at each interval" do
|
85
|
-
result = []
|
86
|
-
|
87
|
-
subject.every(TIMER_QUANTUM * 2) { result << :foo }
|
88
|
-
|
89
|
-
sleep TIMER_QUANTUM * 3
|
90
|
-
subject.fire
|
91
|
-
expect(result).to eq [:foo]
|
92
|
-
|
93
|
-
sleep TIMER_QUANTUM * 5
|
94
|
-
subject.fire
|
95
|
-
expect(result).to eq [:foo, :foo]
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
it "calculates the proper interval to wait until firing" do
|
100
|
-
interval_ms = 25
|
101
|
-
|
102
|
-
subject.after(interval_ms / 1000.0)
|
103
|
-
|
104
|
-
expect(subject.wait_interval).to be_within(TIMER_QUANTUM).of(interval_ms / 1000.0)
|
105
|
-
end
|
106
|
-
|
107
|
-
describe "pause and continue timers" do
|
108
|
-
before(:each) do
|
109
|
-
@interval = TIMER_QUANTUM * 2
|
110
|
-
|
111
|
-
@fired = false
|
112
|
-
@timer = subject.after(@interval) { @fired = true }
|
113
|
-
@fired2 = false
|
114
|
-
@timer2 = subject.after(@interval) { @fired2 = true }
|
115
|
-
end
|
116
|
-
|
117
|
-
it "does not fire when paused" do
|
118
|
-
@timer.pause
|
119
|
-
subject.wait
|
120
|
-
expect(@fired).to be false
|
121
|
-
end
|
122
|
-
|
123
|
-
it "fires when continued after pause" do
|
124
|
-
@timer.pause
|
125
|
-
subject.wait
|
126
|
-
@timer.resume
|
127
|
-
|
128
|
-
sleep @timer.interval
|
129
|
-
subject.wait
|
130
|
-
|
131
|
-
expect(@fired).to be true
|
132
|
-
end
|
133
|
-
|
134
|
-
it "can pause all timers at once" do
|
135
|
-
subject.pause
|
136
|
-
subject.wait
|
137
|
-
expect(@fired).to be false
|
138
|
-
expect(@fired2).to be false
|
139
|
-
end
|
140
|
-
|
141
|
-
it "can continue all timers at once" do
|
142
|
-
subject.pause
|
143
|
-
subject.wait
|
144
|
-
subject.resume
|
145
|
-
|
146
|
-
# We need to wait until we are sure both timers will fire, otherwise highly accurate clocks
|
147
|
-
# (e.g. JVM)may only fire the first timer, but not the second, because they are actually
|
148
|
-
# schedueled at different times.
|
149
|
-
sleep TIMER_QUANTUM * 2
|
150
|
-
subject.wait
|
151
|
-
|
152
|
-
expect(@fired).to be true
|
153
|
-
expect(@fired2).to be true
|
154
|
-
end
|
155
|
-
|
156
|
-
it "can fire the timer directly" do
|
157
|
-
fired = false
|
158
|
-
timer = subject.after(TIMER_QUANTUM * 1) { fired = true }
|
159
|
-
timer.pause
|
160
|
-
subject.wait
|
161
|
-
expect(fired).not_to be true
|
162
|
-
timer.resume
|
163
|
-
expect(fired).not_to be true
|
164
|
-
timer.fire
|
165
|
-
expect(fired).to be true
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
describe "delay timer" do
|
170
|
-
it "adds appropriate amount of time to timer" do
|
171
|
-
timer = subject.after(10)
|
172
|
-
timer.delay(5)
|
173
|
-
expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe "delay timer collection" do
|
178
|
-
it "delay on set adds appropriate amount of time to all timers" do
|
179
|
-
timer = subject.after(10)
|
180
|
-
timer2 = subject.after(20)
|
181
|
-
subject.delay(5)
|
182
|
-
expect(timer.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(15)
|
183
|
-
expect(timer2.offset - subject.current_offset).to be_within(TIMER_QUANTUM).of(25)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe "on delaying a timer" do
|
188
|
-
it "fires timers in the correct order" do
|
189
|
-
result = []
|
190
|
-
|
191
|
-
subject.after(TIMER_QUANTUM * 2) { result << :two }
|
192
|
-
subject.after(TIMER_QUANTUM * 3) { result << :three }
|
193
|
-
first = subject.after(TIMER_QUANTUM * 1) { result << :one }
|
194
|
-
first.delay(TIMER_QUANTUM * 3)
|
195
|
-
|
196
|
-
sleep TIMER_QUANTUM * 5
|
197
|
-
subject.fire
|
198
|
-
|
199
|
-
expect(result).to eq [:two, :three, :one]
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
describe "#inspect" do
|
204
|
-
it "before firing" do
|
205
|
-
fired = false
|
206
|
-
timer = subject.after(TIMER_QUANTUM * 5) { fired = true }
|
207
|
-
timer.pause
|
208
|
-
expect(fired).not_to be true
|
209
|
-
expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fires in [-\.\de]+ seconds>\Z/)
|
210
|
-
end
|
211
|
-
|
212
|
-
it "after firing" do
|
213
|
-
fired = false
|
214
|
-
timer = subject.after(TIMER_QUANTUM) { fired = true }
|
215
|
-
|
216
|
-
subject.wait
|
217
|
-
|
218
|
-
expect(fired).to be true
|
219
|
-
expect(timer.inspect).to match(/\A#<Timers::Timer:[\da-f]+ fired [-\.\de]+ seconds ago>\Z/)
|
220
|
-
end
|
221
|
-
|
222
|
-
it "recurring firing" do
|
223
|
-
result = []
|
224
|
-
timer = subject.every(TIMER_QUANTUM) { result << :foo }
|
225
|
-
|
226
|
-
subject.wait
|
227
|
-
expect(result).not_to be_empty
|
228
|
-
regex = /\A#<Timers::Timer:[\da-f]+ fires in [-\.\de]+ seconds, recurs every #{format("%0.2f", TIMER_QUANTUM)}>\Z/
|
229
|
-
expect(timer.inspect).to match(regex)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
describe "#fires_in" do
|
234
|
-
let(:interval) { TIMER_QUANTUM * 2 }
|
235
|
-
|
236
|
-
it "calculates the interval until the next fire if it's recurring" do
|
237
|
-
timer = subject.every(interval) { true }
|
238
|
-
expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
|
239
|
-
end
|
240
|
-
|
241
|
-
context "when timer is not recurring" do
|
242
|
-
let!(:timer) { subject.after(interval) { true } }
|
243
|
-
|
244
|
-
it "calculates the interval until the next fire if it hasn't already fired" do
|
245
|
-
expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(interval)
|
246
|
-
end
|
247
|
-
|
248
|
-
it "calculates the interval since last fire if already fired" do
|
249
|
-
subject.wait
|
250
|
-
sleep(interval)
|
251
|
-
expect(timer.fires_in).to be_within(TIMER_QUANTUM).of(0 - interval)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Event based timers:
|
4
|
-
|
5
|
-
# Serviced 31812 events in 2.39075272 seconds, 13306.320832794887 e/s.
|
6
|
-
# Thread ID: 7336700
|
7
|
-
# Fiber ID: 30106340
|
8
|
-
# Total: 2.384043
|
9
|
-
# Sort by: self_time
|
10
|
-
|
11
|
-
# %self total self wait child calls name
|
12
|
-
# 13.48 0.510 0.321 0.000 0.189 369133 Timers::Events::Handle#<=>
|
13
|
-
# 8.12 0.194 0.194 0.000 0.000 427278 Timers::Events::Handle#to_f
|
14
|
-
# 4.55 0.109 0.109 0.000 0.000 427278 Float#<=>
|
15
|
-
# 4.40 1.857 0.105 0.000 1.752 466376 *Timers::Events#bsearch
|
16
|
-
# 4.30 0.103 0.103 0.000 0.000 402945 Float#to_f
|
17
|
-
# 2.65 0.063 0.063 0.000 0.000 33812 Array#insert
|
18
|
-
# 2.64 1.850 0.063 0.000 1.787 33812 Timers::Events#schedule
|
19
|
-
# 2.40 1.930 0.057 0.000 1.873 33812 Timers::Timer#reset
|
20
|
-
# 1.89 1.894 0.045 0.000 1.849 31812 Timers::Timer#fire
|
21
|
-
# 1.69 1.966 0.040 0.000 1.926 31812 Timers::Events::Handle#fire
|
22
|
-
# 1.35 0.040 0.032 0.000 0.008 33812 Timers::Events::Handle#initialize
|
23
|
-
# 1.29 0.044 0.031 0.000 0.013 44451 Timers::Group#current_offset
|
24
|
-
|
25
|
-
# SortedSet based timers:
|
26
|
-
|
27
|
-
# Serviced 32516 events in 66.753277275 seconds, 487.1072288781219 e/s.
|
28
|
-
# Thread ID: 15995640
|
29
|
-
# Fiber ID: 38731780
|
30
|
-
# Total: 66.716394
|
31
|
-
# Sort by: self_time
|
32
|
-
|
33
|
-
# %self total self wait child calls name
|
34
|
-
# 54.73 49.718 36.513 0.000 13.205 57084873 Timers::Timer#<=>
|
35
|
-
# 23.74 65.559 15.841 0.000 49.718 32534 Array#sort!
|
36
|
-
# 19.79 13.205 13.205 0.000 0.000 57084873 Float#<=>
|
37
|
-
|
38
|
-
# Max out events performance (on my computer):
|
39
|
-
# Serviced 1142649 events in 11.194903921 seconds, 102068.70405115146 e/s.
|
40
|
-
|
41
|
-
RSpec.describe Timers::Group do
|
42
|
-
it "runs efficiently" do
|
43
|
-
result = []
|
44
|
-
range = (1..500)
|
45
|
-
duration = 2.0
|
46
|
-
|
47
|
-
total = 0
|
48
|
-
range.each do |index|
|
49
|
-
offset = index.to_f / range.max
|
50
|
-
total += (duration / offset).floor
|
51
|
-
|
52
|
-
subject.every(index.to_f / range.max, :strict) { result << index }
|
53
|
-
end
|
54
|
-
|
55
|
-
subject.wait while result.size < total
|
56
|
-
|
57
|
-
rate = result.size.to_f / subject.current_offset
|
58
|
-
puts "Serviced #{result.size} events in #{subject.current_offset} seconds, #{rate} e/s."
|
59
|
-
|
60
|
-
expect(subject.current_offset).to be_within(TIMER_QUANTUM).of(duration)
|
61
|
-
end
|
62
|
-
|
63
|
-
# it "runs efficiently at high volume" do
|
64
|
-
# results = []
|
65
|
-
# range = (1..300)
|
66
|
-
# groups = (1..20)
|
67
|
-
# duration = 101
|
68
|
-
#
|
69
|
-
# timers = []
|
70
|
-
# @mutex = Mutex.new
|
71
|
-
# start = Time.now
|
72
|
-
# groups.each do |gi|
|
73
|
-
# timers << Thread.new {
|
74
|
-
# result = []
|
75
|
-
# timer = Timers::Group.new
|
76
|
-
# total = 0
|
77
|
-
# range.each do |ri|
|
78
|
-
# offset = ri.to_f / range.max
|
79
|
-
# total += (duration / offset).floor
|
80
|
-
# timer.every(ri.to_f / range.max, :strict) { result << ri }
|
81
|
-
# end
|
82
|
-
# timer.wait while result.size < total
|
83
|
-
# @mutex.synchronize { results += result }
|
84
|
-
#
|
85
|
-
# }
|
86
|
-
# end
|
87
|
-
# timers.each { |t| t.join }
|
88
|
-
# finish = Time.now
|
89
|
-
#
|
90
|
-
# rate = results.size.to_f / ( runtime = finish - start )
|
91
|
-
#
|
92
|
-
# puts "Serviced #{results.size} events in #{runtime} seconds, #{rate} e/s; across #{groups.max} timers."
|
93
|
-
#
|
94
|
-
# expect(runtime).to be_within(TIMER_QUANTUM).of(duration)
|
95
|
-
# end
|
96
|
-
end
|
data/spec/timers/strict_spec.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Timers::Group do
|
4
|
-
it "should not diverge too much" do
|
5
|
-
fired = :not_fired_yet
|
6
|
-
count = 0
|
7
|
-
quantum = 0.01
|
8
|
-
|
9
|
-
start_offset = subject.current_offset
|
10
|
-
Timers::Timer.new(subject, quantum, :strict, start_offset) do |offset|
|
11
|
-
fired = offset
|
12
|
-
count += 1
|
13
|
-
end
|
14
|
-
|
15
|
-
iterations = 1000
|
16
|
-
subject.wait while count < iterations
|
17
|
-
|
18
|
-
# In my testing on the JVM, without the :strict recurring, I noticed 60ms of error here.
|
19
|
-
expect(fired - start_offset).to be_within(quantum).of(iterations * quantum)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should only fire once" do
|
23
|
-
fired = :not_fired_yet
|
24
|
-
count = 0
|
25
|
-
|
26
|
-
start_offset = subject.current_offset
|
27
|
-
Timers::Timer.new(subject, 0, :strict, start_offset) do |offset|
|
28
|
-
fired = offset
|
29
|
-
count += 1
|
30
|
-
end
|
31
|
-
|
32
|
-
subject.wait
|
33
|
-
|
34
|
-
expect(count).to be == 1
|
35
|
-
end
|
36
|
-
end
|
data/spec/timers/wait_spec.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
require "timers/wait"
|
5
|
-
|
6
|
-
RSpec.describe Timers::Wait do
|
7
|
-
it "repeats until timeout expired" do
|
8
|
-
timeout = Timers::Wait.new(5)
|
9
|
-
count = 0
|
10
|
-
|
11
|
-
timeout.while_time_remaining do |remaining|
|
12
|
-
expect(remaining).to be_within(TIMER_QUANTUM).of(timeout.duration - count)
|
13
|
-
|
14
|
-
count += 1
|
15
|
-
sleep 1
|
16
|
-
end
|
17
|
-
|
18
|
-
expect(count).to eq(5)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "yields results as soon as possible" do
|
22
|
-
timeout = Timers::Wait.new(5)
|
23
|
-
|
24
|
-
result = timeout.while_time_remaining do |_remaining|
|
25
|
-
break :done
|
26
|
-
end
|
27
|
-
|
28
|
-
expect(result).to eq(:done)
|
29
|
-
end
|
30
|
-
end
|
data/timers.gemspec
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require File.expand_path("../lib/timers/version", __FILE__)
|
5
|
-
|
6
|
-
Gem::Specification.new do |gem|
|
7
|
-
gem.name = "timers"
|
8
|
-
gem.version = Timers::VERSION
|
9
|
-
gem.authors = ["Tony Arcieri"]
|
10
|
-
gem.email = ["bascule@gmail.com"]
|
11
|
-
gem.licenses = ["MIT"]
|
12
|
-
gem.homepage = "https://github.com/celluloid/timers"
|
13
|
-
gem.summary = "Pure Ruby one-shot and periodic timers"
|
14
|
-
gem.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
|
15
|
-
Schedule procs to run after a certain time, or at periodic intervals,
|
16
|
-
using any API that accepts a timeout.
|
17
|
-
DESCRIPTION
|
18
|
-
|
19
|
-
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
20
|
-
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
21
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
|
-
gem.require_paths = ["lib"]
|
23
|
-
gem.add_runtime_dependency "hitimes"
|
24
|
-
|
25
|
-
gem.add_development_dependency "bundler"
|
26
|
-
end
|