evt-poll 0.1.0.0

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: 89cf5f449b8dcf01f48c82d39a139434ea8ac185c7178bac749c4394de174bf7
4
+ data.tar.gz: d24ea1791c7bf0400b32b33a83fa07963f700623ed3169dff10967ed417f18f3
5
+ SHA512:
6
+ metadata.gz: 0f875934c022770e5b14eed4b066326ec0c0faf60bb48d8e09450d508e72d20c398dbda654124a0337a8ca484c05ea16f9b1ae392fcac0f1b1220f8d821c55f7
7
+ data.tar.gz: ea00a5edf1896470713a6cb76cd516ae97f19a99e8832f7c54f63aa7cc2525b96521f2b976173d431119587c46c17eee8b7db3397e1aab98a41e35b74d163821
data/lib/poll.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'log'
2
+ require 'telemetry'
3
+ require 'clock'
4
+
5
+ require 'poll/log'
6
+ require 'poll/cycle'
7
+ require 'poll/defaults'
@@ -0,0 +1,3 @@
1
+ require 'clock/controls'
2
+
3
+ require 'poll/controls/time'
@@ -0,0 +1,5 @@
1
+ class Poll
2
+ module Controls
3
+ Time = Clock::Controls::Time
4
+ end
5
+ end
data/lib/poll/cycle.rb ADDED
@@ -0,0 +1,179 @@
1
+ class Poll
2
+ Error = Class.new(RuntimeError)
3
+
4
+ include Log::Dependency
5
+
6
+ dependency :clock, Clock::UTC
7
+ dependency :telemetry, Telemetry
8
+
9
+ attr_writer :interval_milliseconds
10
+ def interval_milliseconds
11
+ @interval_milliseconds ||= Defaults.interval_milliseconds
12
+ end
13
+
14
+ attr_accessor :timeout_milliseconds
15
+
16
+ attr_writer :delay_condition
17
+ def delay_condition
18
+ @delay_condition ||= Defaults.delay_condition
19
+ end
20
+
21
+ def self.build(interval_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil)
22
+ instance = new
23
+
24
+ instance.interval_milliseconds = interval_milliseconds
25
+ instance.timeout_milliseconds = timeout_milliseconds
26
+ instance.delay_condition = delay_condition
27
+
28
+ instance.configure
29
+
30
+ instance
31
+ end
32
+
33
+ def self.configure(receiver, attr_name: nil, interval_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil, cycle: nil)
34
+ attr_name ||= :cycle
35
+
36
+ if !cycle.nil?
37
+ instance = cycle
38
+ else
39
+ instance = build(interval_milliseconds: interval_milliseconds, timeout_milliseconds: timeout_milliseconds, delay_condition: delay_condition)
40
+ end
41
+
42
+ receiver.public_send "#{attr_name}=", instance
43
+ end
44
+
45
+ def self.none
46
+ None.build
47
+ end
48
+
49
+ def configure
50
+ Clock::UTC.configure self
51
+ ::Telemetry.configure self
52
+ end
53
+
54
+ def self.call(interval_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil, &action)
55
+ instance = build(interval_milliseconds: interval_milliseconds, timeout_milliseconds: timeout_milliseconds, delay_condition: delay_condition)
56
+ instance.call(&action)
57
+ end
58
+
59
+ def call(&action)
60
+ stop_time = nil
61
+ stop_time_iso8601 = nil
62
+ if !timeout_milliseconds.nil?
63
+ stop_time = clock.now + (timeout_milliseconds.to_f / 1000.0)
64
+ stop_time_iso8601 = clock.iso8601(stop_time, precision: 5)
65
+ end
66
+
67
+ logger.trace { "Cycling (Interval Milliseconds: #{interval_milliseconds}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601})" }
68
+
69
+ cycle = -1
70
+ result = nil
71
+ loop do
72
+ cycle += 1
73
+ telemetry.record :cycle, cycle
74
+
75
+ result, elapsed_milliseconds = invoke(cycle, &action)
76
+
77
+ if delay_condition.(result)
78
+ logger.debug { "Got no results from action (Cycle: #{cycle})" }
79
+ delay(elapsed_milliseconds)
80
+ else
81
+ logger.debug { "Got results from action (Cycle: #{cycle})" }
82
+ telemetry.record :got_result
83
+ break
84
+ end
85
+
86
+ if !timeout_milliseconds.nil?
87
+ now = clock.now
88
+ if now >= stop_time
89
+ logger.debug { "Timeout has lapsed (Cycle: #{cycle}, Stop Time: #{stop_time_iso8601}, Timeout Milliseconds: #{timeout_milliseconds})" }
90
+ telemetry.record :timed_out, now
91
+ break
92
+ end
93
+ end
94
+ end
95
+
96
+ logger.debug { "Cycled (Iterations: #{cycle + 1}, Interval Milliseconds: #{interval_milliseconds}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601})" }
97
+
98
+ return result
99
+ end
100
+
101
+ def invoke(cycle, &action)
102
+ if action.nil?
103
+ raise Error, "Poll must be actuated with a block"
104
+ end
105
+
106
+ action_start_time = clock.now
107
+
108
+ logger.trace { "Invoking action (Cycle: #{cycle}, Start Time: #{clock.iso8601(action_start_time, precision: 5)})" }
109
+
110
+ result = action.call(cycle)
111
+
112
+ action_end_time = clock.now
113
+ elapsed_milliseconds = clock.elapsed_milliseconds(action_start_time, action_end_time)
114
+
115
+ telemetry.record :invoked_action, elapsed_milliseconds
116
+
117
+ logger.debug { "Invoked action (Cycle: #{cycle}, Elapsed Milliseconds: #{elapsed_milliseconds}, Start Time: #{clock.iso8601(action_start_time, precision: 5)}, End Time: #{clock.iso8601(action_end_time, precision: 5)})" }
118
+
119
+ [result, elapsed_milliseconds]
120
+ end
121
+
122
+ def delay(elapsed_milliseconds)
123
+ delay_milliseconds = interval_milliseconds - elapsed_milliseconds
124
+
125
+ logger.trace { "Delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
126
+
127
+ if delay_milliseconds <= 0
128
+ logger.debug { "Elapsed time exceeds or equals interval. Not delayed. (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
129
+ return
130
+ end
131
+
132
+ delay_seconds = (delay_milliseconds.to_f / 1000.0)
133
+
134
+ sleep delay_seconds
135
+
136
+ telemetry.record :delayed, delay_milliseconds
137
+
138
+ logger.debug { "Finished delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
139
+ end
140
+
141
+ def self.register_telemetry_sink(cycle)
142
+ sink = Telemetry.sink
143
+ cycle.telemetry.register(sink)
144
+ sink
145
+ end
146
+
147
+ module Telemetry
148
+ class Sink
149
+ include ::Telemetry::Sink
150
+
151
+ record :cycle
152
+ record :invoked_action
153
+ record :got_result
154
+ record :delayed
155
+ record :timed_out
156
+ end
157
+
158
+ def self.sink
159
+ Sink.new
160
+ end
161
+ end
162
+
163
+ module Substitute
164
+ def self.build
165
+ instance = Poll.build(timeout_milliseconds: 0)
166
+
167
+ sink = Poll.register_telemetry_sink(instance)
168
+ instance.telemetry_sink = sink
169
+
170
+ instance.configure
171
+
172
+ instance
173
+ end
174
+
175
+ class Poll < ::Poll
176
+ attr_accessor :telemetry_sink
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,17 @@
1
+ class Poll
2
+ module Defaults
3
+ def self.interval_milliseconds
4
+ 0
5
+ end
6
+
7
+ def self.delay_condition
8
+ lambda do |result|
9
+ if result.respond_to?(:empty?)
10
+ result.empty?
11
+ else
12
+ result.nil?
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/poll/log.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Poll
2
+ class Log < ::Log
3
+ def tag!(tags)
4
+ tags << :cycle
5
+ tags << :library
6
+ tags << :verbose
7
+ end
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evt-poll
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-07 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/poll.rb
76
+ - lib/poll/controls.rb
77
+ - lib/poll/controls/time.rb
78
+ - lib/poll/cycle.rb
79
+ - lib/poll/defaults.rb
80
+ - lib/poll/log.rb
81
+ homepage: https://github.com/eventide-project/cycle
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '2.4'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.7.3
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Generalized implementation of polling
105
+ test_files: []