evt-cycle 0.6.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aad5ab4322e5cade73e5c45e43c4088ae827bf9e4f58df25bcd0beca8f70ad84
4
+ data.tar.gz: eb00b19da06bf84f666391d2ac4b1ced0f3de9013193209a6eaf01ac25087ac8
5
+ SHA512:
6
+ metadata.gz: 6fcb6d3558c9b9ac2abcc7ea2e7373ffe893980af92facd65ca18751ff65daa2e550da45c03e4247b88866f11461b01cce7aedc4f36a873ec3149570a56eaa06
7
+ data.tar.gz: 1f70b16b86a6ea45d800ea98a8191d3f2921a93825c92071e0f9eb6c5497fc8564cb4106891bf14729f8cb9133691116cecbdde1349918abd7cbd650b223046c
@@ -0,0 +1,8 @@
1
+ require 'log'
2
+ require 'telemetry'
3
+ require 'clock'
4
+ require 'initializer'; Initializer.activate
5
+
6
+ require 'cycle/log'
7
+ require 'cycle/cycle'
8
+ require 'cycle/defaults'
@@ -0,0 +1,3 @@
1
+ require 'clock/controls'
2
+
3
+ require 'cycle/controls/time'
@@ -0,0 +1,5 @@
1
+ class Cycle
2
+ module Controls
3
+ Time = Clock::Controls::Time
4
+ end
5
+ end
@@ -0,0 +1,179 @@
1
+ class Cycle
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, "Cycle 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 = Cycle.build(timeout_milliseconds: 0)
166
+
167
+ sink = Cycle.register_telemetry_sink(instance)
168
+ instance.telemetry_sink = sink
169
+
170
+ instance.configure
171
+
172
+ instance
173
+ end
174
+
175
+ class Cycle < ::Cycle
176
+ attr_accessor :telemetry_sink
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,17 @@
1
+ class Cycle
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
@@ -0,0 +1,9 @@
1
+ class Cycle
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,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evt-cycle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0.0
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-10 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: evt-initializer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: test_bench
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: " "
84
+ email: opensource@eventide-project.org
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - lib/cycle.rb
90
+ - lib/cycle/controls.rb
91
+ - lib/cycle/controls/time.rb
92
+ - lib/cycle/cycle.rb
93
+ - lib/cycle/defaults.rb
94
+ - lib/cycle/log.rb
95
+ homepage: https://github.com/eventide-project/cycle
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 2.3.3
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.7.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Generalized retry
119
+ test_files: []