evt-wait 2.0.1.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bca2702e59c02ee267536fcdef906db0bb76d5c2eddc64abbd6cbec0f0057731
4
+ data.tar.gz: 2b571bae744dad9731a0c90b35e417199603d3d29c7dcde17728b8fb2c6bdada
5
+ SHA512:
6
+ metadata.gz: bc83aa97f8703d2f68fae17bec1d99801df345d9743d57cb88e46062fe77f24fb805f05a394a3c8cc819ec83f618d13972a095477398904552cdabb5d2a86b98
7
+ data.tar.gz: 8ec8d89999fc8816510af933c73bdd5384a78bb91252bd1da0581ac877f65dbf9bb5c77b50a427a6a255b6de30f83d364e185f565859c08cbed19efa1119d4d9
@@ -0,0 +1,5 @@
1
+ class Wait
2
+ module Controls
3
+ Time = Clock::Controls::Time
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'clock/controls'
2
+
3
+ require 'wait/controls/time'
data/lib/wait/log.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Wait
2
+ class Log < ::Log
3
+ def tag!(tags)
4
+ tags << :until
5
+ tags << :library
6
+ tags << :verbose
7
+ end
8
+ end
9
+ end
data/lib/wait/wait.rb ADDED
@@ -0,0 +1,169 @@
1
+ class Wait
2
+ Error = Class.new(RuntimeError)
3
+ NoBlockError = Class.new(Error)
4
+ TimeoutError = Class.new(Error)
5
+ ResultTypeError = Class.new(Error)
6
+
7
+ include Dependency
8
+ include Log::Dependency
9
+
10
+ dependency :clock, Clock::UTC
11
+ dependency :telemetry, Telemetry
12
+
13
+ def self.build
14
+ instance = new
15
+ instance.configure
16
+ instance
17
+ end
18
+
19
+ def self.configure(receiver, attr_name: nil)
20
+ attr_name ||= :wait
21
+ instance = build
22
+ receiver.public_send("#{attr_name}=", instance)
23
+ end
24
+
25
+ def configure
26
+ Clock::UTC.configure(self)
27
+ ::Telemetry.configure(self)
28
+ end
29
+
30
+ def self.call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition)
31
+ instance = build
32
+ instance.call(interval_milliseconds: interval_milliseconds, timeout_milliseconds: timeout_milliseconds, &condition)
33
+ end
34
+
35
+ def call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition)
36
+ interval_milliseconds ||= Defaults.interval_milliseconds
37
+
38
+ if condition.nil?
39
+ raise NoBlockError, "Wait must be actuated with a block"
40
+ end
41
+
42
+ stop_time = nil
43
+ stop_time_iso8601 = nil
44
+ if not timeout_milliseconds.nil?
45
+ stop_time = clock.now + (timeout_milliseconds.to_f / 1000.0)
46
+ stop_time_iso8601 = clock.iso8601(stop_time, precision: 5)
47
+ end
48
+
49
+ logger.trace { "Cycling (Interval Milliseconds: #{interval_milliseconds.inspect}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601.inspect})" }
50
+
51
+ cycle = -1
52
+ result = nil
53
+ loop do
54
+ cycle += 1
55
+ telemetry.record(:cycle, cycle)
56
+
57
+ result, elapsed_milliseconds = evaluate_condition(cycle, &condition)
58
+
59
+ if result.nil?
60
+ result = false
61
+ end
62
+
63
+ if not (result.is_a?(TrueClass) || result.is_a?(FalseClass))
64
+ raise ResultTypeError, "The block result must be boolean (Result: #{result.inspect})"
65
+ end
66
+
67
+ if result == true
68
+ logger.debug { "Cycle condition is met (Cycle: #{cycle})" }
69
+ telemetry.record(:condition_satisfied)
70
+ break
71
+ end
72
+
73
+ delay(interval_milliseconds, elapsed_milliseconds)
74
+
75
+ if !timeout_milliseconds.nil?
76
+ now = clock.now
77
+ if now >= stop_time
78
+ logger.debug { "Timeout has lapsed (Cycle: #{cycle}, Stop Time: #{stop_time_iso8601}, Timeout Milliseconds: #{timeout_milliseconds.inspect})" }
79
+ telemetry.record(:timed_out, now)
80
+ break
81
+ end
82
+ end
83
+ end
84
+
85
+ logger.debug { "Cycled (Cycles: #{cycle + 1}, Interval Milliseconds: #{interval_milliseconds.inspect}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601})" }
86
+
87
+ cycle_count = cycle + 1
88
+
89
+ return cycle_count
90
+ end
91
+
92
+ def evaluate_condition(cycle, &condition)
93
+ condition_start_time = clock.now
94
+
95
+ logger.trace { "Evaluating condition (Cycle: #{cycle}, Start Time: #{clock.iso8601(condition_start_time, precision: 5)})" }
96
+
97
+ result = condition.call(cycle)
98
+
99
+ condition_end_time = clock.now
100
+ elapsed_milliseconds = clock.elapsed_milliseconds(condition_start_time, condition_end_time)
101
+
102
+ logger.debug { "Evaluated condition (Cycle: #{cycle}, Elapsed Milliseconds: #{elapsed_milliseconds}, Start Time: #{clock.iso8601(condition_start_time, precision: 5)}, End Time: #{clock.iso8601(condition_end_time, precision: 5)})" }
103
+
104
+ [result, elapsed_milliseconds]
105
+ end
106
+
107
+ def delay(interval_milliseconds, elapsed_milliseconds)
108
+ delay_milliseconds = interval_milliseconds - elapsed_milliseconds
109
+
110
+ logger.trace { "Delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
111
+
112
+ if delay_milliseconds <= 0
113
+ logger.debug { "Elapsed time exceeds or equals interval. Not delayed. (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
114
+ return
115
+ end
116
+
117
+ delay_seconds = (delay_milliseconds.to_f / 1000.0)
118
+
119
+ sleep delay_seconds
120
+
121
+ telemetry.record(:delayed, delay_milliseconds)
122
+
123
+ logger.debug { "Finished delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
124
+ end
125
+
126
+ def self.register_telemetry_sink(cycle)
127
+ sink = Telemetry.sink
128
+ cycle.telemetry.register(sink)
129
+ sink
130
+ end
131
+
132
+ module Defaults
133
+ def self.interval_milliseconds
134
+ 0
135
+ end
136
+ end
137
+
138
+ module Telemetry
139
+ class Sink
140
+ include ::Telemetry::Sink
141
+
142
+ record :cycle
143
+ record :condition_satisfied
144
+ record :delayed
145
+ record :timed_out
146
+ end
147
+
148
+ def self.sink
149
+ Sink.new
150
+ end
151
+ end
152
+
153
+ module Substitute
154
+ def self.build
155
+ instance = Wait.build
156
+
157
+ sink = Wait.register_telemetry_sink(instance)
158
+ instance.telemetry_sink = sink
159
+
160
+ instance.configure
161
+
162
+ instance
163
+ end
164
+
165
+ class Wait < ::Wait
166
+ attr_accessor :telemetry_sink
167
+ end
168
+ end
169
+ end
data/lib/wait.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'log'
2
+ require 'telemetry'
3
+ require 'clock'
4
+
5
+ require 'wait/log'
6
+ require 'wait/wait'
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evt-wait
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: evt-log
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: evt-telemetry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: evt-clock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test_bench
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: " "
70
+ email: opensource@eventide-project.org
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - lib/wait.rb
76
+ - lib/wait/controls.rb
77
+ - lib/wait/controls/time.rb
78
+ - lib/wait/log.rb
79
+ - lib/wait/wait.rb
80
+ homepage: https://github.com/eventide-project/wait
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '2.4'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubygems_version: 3.3.3
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Generalized implementation of execution-until-condition with support for
103
+ timeout and polling interval
104
+ test_files: []