rsmp 0.8.5 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yaml +21 -0
- data/Gemfile.lock +9 -3
- data/README.md +2 -12
- data/bin/console +1 -1
- data/cucumber.yml +1 -0
- data/documentation/classes_and_modules.md +4 -4
- data/documentation/collecting_message.md +2 -2
- data/documentation/tasks.md +149 -0
- data/lib/rsmp/archive.rb +3 -3
- data/lib/rsmp/cli.rb +32 -4
- data/lib/rsmp/collect/aggregated_status_collector.rb +1 -1
- data/lib/rsmp/collect/command_response_collector.rb +1 -1
- data/lib/rsmp/collect/state_collector.rb +1 -1
- data/lib/rsmp/collect/status_collector.rb +2 -1
- data/lib/rsmp/components.rb +3 -3
- data/lib/rsmp/convert/export/json_schema.rb +4 -4
- data/lib/rsmp/convert/import/yaml.rb +1 -1
- data/lib/rsmp/deep_merge.rb +1 -0
- data/lib/rsmp/error.rb +0 -3
- data/lib/rsmp/inspect.rb +1 -1
- data/lib/rsmp/logger.rb +5 -5
- data/lib/rsmp/logging.rb +1 -1
- data/lib/rsmp/message.rb +1 -1
- data/lib/rsmp/node.rb +10 -45
- data/lib/rsmp/proxy.rb +176 -133
- data/lib/rsmp/rsmp.rb +1 -1
- data/lib/rsmp/site.rb +23 -60
- data/lib/rsmp/site_proxy.rb +21 -17
- data/lib/rsmp/supervisor.rb +25 -21
- data/lib/rsmp/supervisor_proxy.rb +58 -29
- data/lib/rsmp/task.rb +84 -0
- data/lib/rsmp/tlc/signal_group.rb +7 -5
- data/lib/rsmp/tlc/signal_plan.rb +2 -2
- data/lib/rsmp/tlc/traffic_controller.rb +146 -53
- data/lib/rsmp/tlc/traffic_controller_site.rb +43 -36
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +1 -1
- metadata +6 -5
- data/lib/rsmp/site_proxy_wait.rb +0 -0
- data/lib/rsmp/wait.rb +0 -16
- data/test.rb +0 -27
data/lib/rsmp/node.rb
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
module RSMP
|
4
4
|
class Node
|
5
5
|
include Logging
|
6
|
-
include Wait
|
7
6
|
include Inspect
|
7
|
+
include Task
|
8
8
|
|
9
9
|
attr_reader :archive, :logger, :task, :deferred, :error_queue, :clock, :collector
|
10
10
|
|
11
11
|
def initialize options
|
12
12
|
initialize_logging options
|
13
|
-
|
13
|
+
initialize_task
|
14
14
|
@deferred = []
|
15
15
|
@clock = Clock.new
|
16
16
|
@error_queue = Async::Queue.new
|
@@ -18,6 +18,13 @@ module RSMP
|
|
18
18
|
@collect = options[:collect]
|
19
19
|
end
|
20
20
|
|
21
|
+
# stop proxies, then call super
|
22
|
+
def stop_subtasks
|
23
|
+
@proxies.each { |proxy| proxy.stop }
|
24
|
+
@proxies.clear
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
21
28
|
def ignore_errors classes, &block
|
22
29
|
was, @ignore_errors = @ignore_errors, [classes].flatten
|
23
30
|
yield
|
@@ -50,55 +57,13 @@ module RSMP
|
|
50
57
|
|
51
58
|
def clear_deferred
|
52
59
|
@deferred.clear
|
53
|
-
end
|
54
|
-
|
55
|
-
def do_start task
|
56
|
-
task.annotate self.class.to_s
|
57
|
-
@task = task
|
58
|
-
start_action
|
59
|
-
idle
|
60
|
-
end
|
61
|
-
|
62
|
-
def start
|
63
|
-
starting
|
64
|
-
if @task
|
65
|
-
do_start @task
|
66
|
-
else
|
67
|
-
Async do |task|
|
68
|
-
do_start task
|
69
|
-
end
|
70
|
-
end
|
71
|
-
rescue Errno::EADDRINUSE => e
|
72
|
-
log "Cannot start: #{e.to_s}", level: :error
|
73
|
-
rescue SystemExit, SignalException, Interrupt
|
74
|
-
@logger.unmute_all
|
75
|
-
exiting
|
76
|
-
end
|
77
|
-
|
78
|
-
def idle
|
79
|
-
loop do
|
80
|
-
@task.sleep 60
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def stop
|
85
|
-
@task.stop if @task
|
86
|
-
end
|
87
|
-
|
88
|
-
def restart
|
89
|
-
stop
|
90
|
-
start
|
91
|
-
end
|
92
|
-
|
93
|
-
def exiting
|
94
|
-
log "Exiting", level: :info
|
95
60
|
end
|
96
61
|
|
97
62
|
def check_required_settings settings, required
|
98
63
|
raise ArgumentError.new "Settings is empty" unless settings
|
99
64
|
required.each do |setting|
|
100
65
|
raise ArgumentError.new "Missing setting: #{setting}" unless settings.include? setting.to_s
|
101
|
-
end
|
66
|
+
end
|
102
67
|
end
|
103
68
|
|
104
69
|
def author
|
data/lib/rsmp/proxy.rb
CHANGED
@@ -1,32 +1,104 @@
|
|
1
|
-
#
|
1
|
+
# A connection to a remote site or supervisor.
|
2
|
+
# Uses the Task module to handle asyncronous work, but adds
|
3
|
+
# the concept of a connection that can be connected or disconnected.
|
2
4
|
|
3
5
|
require 'rubygems'
|
4
6
|
|
5
|
-
module RSMP
|
7
|
+
module RSMP
|
6
8
|
class Proxy
|
7
9
|
WRAPPING_DELIMITER = "\f"
|
8
10
|
|
9
11
|
include Logging
|
10
|
-
include Wait
|
11
12
|
include Notifier
|
12
13
|
include Inspect
|
14
|
+
include Task
|
13
15
|
|
14
|
-
attr_reader :state, :archive, :connection_info, :sxl, :
|
16
|
+
attr_reader :state, :archive, :connection_info, :sxl, :collector, :ip, :port
|
15
17
|
|
16
18
|
def initialize options
|
17
19
|
initialize_logging options
|
18
20
|
initialize_distributor
|
21
|
+
initialize_task
|
19
22
|
setup options
|
20
23
|
clear
|
24
|
+
@state = :disconnected
|
21
25
|
end
|
22
26
|
|
27
|
+
def disconnect
|
28
|
+
end
|
29
|
+
|
30
|
+
# wait for the reader task to complete,
|
31
|
+
# which is not expected to happen before the connection is closed
|
32
|
+
def wait_for_reader
|
33
|
+
@reader.wait if @reader
|
34
|
+
end
|
35
|
+
|
36
|
+
# close connection, but keep our main task running so we can reconnect
|
37
|
+
def close
|
38
|
+
log "Closing connection", level: :warning
|
39
|
+
close_stream
|
40
|
+
close_socket
|
41
|
+
set_state :disconnected
|
42
|
+
notify_error DisconnectError.new("Connection was closed")
|
43
|
+
stop_timer
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop_subtasks
|
47
|
+
stop_timer
|
48
|
+
stop_reader
|
49
|
+
clear
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def stop_timer
|
54
|
+
return unless @timer
|
55
|
+
@timer.stop
|
56
|
+
@timer = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def stop_reader
|
60
|
+
return unless @reader
|
61
|
+
@reader.stop
|
62
|
+
@reader = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def close_stream
|
66
|
+
return unless @stream
|
67
|
+
@stream.close
|
68
|
+
@stream = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def close_socket
|
72
|
+
return unless @socket
|
73
|
+
@socket.close
|
74
|
+
@socket = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def stop_task
|
78
|
+
close
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
# change our state
|
83
|
+
def set_state state
|
84
|
+
return if state == @state
|
85
|
+
@state = state
|
86
|
+
state_changed
|
87
|
+
end
|
88
|
+
|
89
|
+
# the state changed
|
90
|
+
# override to to things like notifications
|
91
|
+
def state_changed
|
92
|
+
@state_condition.signal @state
|
93
|
+
end
|
94
|
+
|
95
|
+
# revive after a reconnect
|
23
96
|
def revive options
|
24
97
|
setup options
|
25
98
|
end
|
26
99
|
|
27
100
|
def setup options
|
28
101
|
@settings = options[:settings]
|
29
|
-
@task = options[:task]
|
30
102
|
@socket = options[:socket]
|
31
103
|
@stream = options[:stream]
|
32
104
|
@protocol = options[:protocol]
|
@@ -35,7 +107,6 @@ module RSMP
|
|
35
107
|
@connection_info = options[:info]
|
36
108
|
@sxl = nil
|
37
109
|
@site_settings = nil # can't pick until we know the site id
|
38
|
-
@state = :stopped
|
39
110
|
if options[:collect]
|
40
111
|
@collector = RSMP::Collector.new self, options[:collect]
|
41
112
|
@collector.start
|
@@ -52,35 +123,16 @@ module RSMP
|
|
52
123
|
node.clock
|
53
124
|
end
|
54
125
|
|
55
|
-
def run
|
56
|
-
start
|
57
|
-
@reader.wait if @reader
|
58
|
-
ensure
|
59
|
-
stop unless [:stopped, :stopping].include? @state
|
60
|
-
end
|
61
|
-
|
62
126
|
def ready?
|
63
127
|
@state == :ready
|
64
128
|
end
|
65
129
|
|
66
130
|
def connected?
|
67
|
-
@state == :
|
131
|
+
@state == :connected || @state == :ready
|
68
132
|
end
|
69
133
|
|
70
|
-
|
71
|
-
|
72
|
-
set_state :starting
|
73
|
-
end
|
74
|
-
|
75
|
-
def stop
|
76
|
-
return if @state == :stopped
|
77
|
-
set_state :stopping
|
78
|
-
stop_tasks
|
79
|
-
notify_error DisconnectError.new("Connection was closed")
|
80
|
-
ensure
|
81
|
-
close_socket
|
82
|
-
clear
|
83
|
-
set_state :stopped
|
134
|
+
def disconnected?
|
135
|
+
@state == :disconnected
|
84
136
|
end
|
85
137
|
|
86
138
|
def clear
|
@@ -97,56 +149,57 @@ module RSMP
|
|
97
149
|
@acknowledgement_condition = Async::Notification.new
|
98
150
|
end
|
99
151
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if @socket
|
107
|
-
@socket.close
|
108
|
-
@socket = nil
|
152
|
+
# run an async task that reads from @socket
|
153
|
+
def start_reader
|
154
|
+
@reader = @task.async do |task|
|
155
|
+
task.annotate "reader"
|
156
|
+
run_reader
|
109
157
|
end
|
110
158
|
end
|
111
159
|
|
112
|
-
def
|
113
|
-
@
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
160
|
+
def run_reader
|
161
|
+
@stream ||= Async::IO::Stream.new(@socket)
|
162
|
+
@protocol ||= Async::IO::Protocol::Line.new(@stream,WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
|
163
|
+
loop do
|
164
|
+
read_line
|
165
|
+
end
|
166
|
+
rescue Restart
|
167
|
+
log "Closing connection", level: :warning
|
168
|
+
raise
|
169
|
+
rescue Async::Wrapper::Cancelled
|
170
|
+
# ignore exceptions raised when a wait is aborted because a task is stopped
|
171
|
+
rescue EOFError, Async::Stop
|
172
|
+
log "Connection closed", level: :warning
|
173
|
+
rescue IOError => e
|
174
|
+
log "IOError: #{e}", level: :warning
|
175
|
+
rescue Errno::ECONNRESET
|
176
|
+
log "Connection reset by peer", level: :warning
|
177
|
+
rescue Errno::EPIPE
|
178
|
+
log "Broken pipe", level: :warning
|
179
|
+
rescue StandardError => e
|
180
|
+
notify_error e, level: :internal
|
181
|
+
end
|
182
|
+
|
183
|
+
def read_line
|
184
|
+
json = @protocol.read_line
|
185
|
+
beginning = Time.now
|
186
|
+
message = process_packet json
|
187
|
+
duration = Time.now - beginning
|
188
|
+
ms = (duration*1000).round(4)
|
189
|
+
if duration > 0
|
190
|
+
per_second = (1.0 / duration).round
|
191
|
+
else
|
192
|
+
per_second = Float::INFINITY
|
193
|
+
end
|
194
|
+
if message
|
195
|
+
type = message.type
|
196
|
+
m_id = Logger.shorten_message_id(message.m_id)
|
197
|
+
else
|
198
|
+
type = 'Unknown'
|
199
|
+
m_id = nil
|
149
200
|
end
|
201
|
+
str = [type,m_id,"processed in #{ms}ms, #{per_second}req/s"].compact.join(' ')
|
202
|
+
log str, level: :statistics
|
150
203
|
end
|
151
204
|
|
152
205
|
def notify_error e, options={}
|
@@ -160,36 +213,40 @@ module RSMP
|
|
160
213
|
end
|
161
214
|
|
162
215
|
def start_timer
|
216
|
+
return if @timer
|
163
217
|
name = "timer"
|
164
218
|
interval = @site_settings['intervals']['timer'] || 1
|
165
219
|
log "Starting #{name} with interval #{interval} seconds", level: :debug
|
166
220
|
@latest_watchdog_received = Clock.now
|
167
|
-
|
168
221
|
@timer = @task.async do |task|
|
169
222
|
task.annotate "timer"
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
223
|
+
run_timer task, interval
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def run_timer task, interval
|
228
|
+
next_time = Time.now.to_f
|
229
|
+
loop do
|
230
|
+
begin
|
231
|
+
now = Clock.now
|
232
|
+
timer(now)
|
233
|
+
rescue RSMP::Schemer::Error => e
|
234
|
+
log "Timer: Schema error: #{e}", level: :warning
|
235
|
+
rescue EOFError => e
|
236
|
+
log "Timer: Connection closed: #{e}", level: :warning
|
237
|
+
rescue IOError => e
|
238
|
+
log "Timer: IOError", level: :warning
|
239
|
+
rescue Errno::ECONNRESET
|
240
|
+
log "Timer: Connection reset by peer", level: :warning
|
241
|
+
rescue Errno::EPIPE => e
|
242
|
+
log "Timer: Broken pipe", level: :warning
|
243
|
+
rescue StandardError => e
|
244
|
+
notify_error e, level: :internal
|
192
245
|
end
|
246
|
+
ensure
|
247
|
+
next_time += interval
|
248
|
+
duration = next_time - Time.now.to_f
|
249
|
+
task.sleep duration
|
193
250
|
end
|
194
251
|
end
|
195
252
|
|
@@ -200,7 +257,7 @@ module RSMP
|
|
200
257
|
end
|
201
258
|
|
202
259
|
def watchdog_send_timer now
|
203
|
-
return unless @watchdog_started
|
260
|
+
return unless @watchdog_started
|
204
261
|
return if @site_settings['intervals']['watchdog'] == :never
|
205
262
|
if @latest_watchdog_send_at == nil
|
206
263
|
send_watchdog now
|
@@ -226,9 +283,13 @@ module RSMP
|
|
226
283
|
@awaiting_acknowledgement.clone.each_pair do |m_id, message|
|
227
284
|
latest = message.timestamp + timeout
|
228
285
|
if now > latest
|
229
|
-
|
230
|
-
|
231
|
-
|
286
|
+
str = "No acknowledgements for #{message.type} #{message.m_id_short} within #{timeout} seconds"
|
287
|
+
log str, level: :error
|
288
|
+
begin
|
289
|
+
close
|
290
|
+
ensure
|
291
|
+
notify_error MissingAcknowledgment.new(str)
|
292
|
+
end
|
232
293
|
end
|
233
294
|
end
|
234
295
|
end
|
@@ -238,16 +299,16 @@ module RSMP
|
|
238
299
|
latest = @latest_watchdog_received + timeout
|
239
300
|
left = latest - now
|
240
301
|
if left < 0
|
241
|
-
|
242
|
-
|
302
|
+
str = "No Watchdog within #{timeout} seconds"
|
303
|
+
log str, level: :error
|
304
|
+
begin
|
305
|
+
close # this will stop the current task (ourself)
|
306
|
+
ensure
|
307
|
+
notify_error MissingWatchdog.new(str) # but ensure block will still be reached
|
308
|
+
end
|
243
309
|
end
|
244
310
|
end
|
245
311
|
|
246
|
-
def stop_tasks
|
247
|
-
@timer.stop if @timer
|
248
|
-
@reader.stop if @reader
|
249
|
-
end
|
250
|
-
|
251
312
|
def log str, options={}
|
252
313
|
super str, options.merge(ip: @ip, port: @port, site_id: @site_id)
|
253
314
|
end
|
@@ -355,7 +416,7 @@ module RSMP
|
|
355
416
|
str = "Rejected #{message.type},"
|
356
417
|
notify_error e.exception(str), message: message
|
357
418
|
dont_acknowledge message, str, reason
|
358
|
-
|
419
|
+
close
|
359
420
|
message
|
360
421
|
ensure
|
361
422
|
node.clear_deferred
|
@@ -436,19 +497,14 @@ module RSMP
|
|
436
497
|
send_message message, "for #{original.type} #{original.m_id_short}"
|
437
498
|
end
|
438
499
|
|
439
|
-
def
|
440
|
-
@state = state
|
441
|
-
@state_condition.signal @state
|
442
|
-
end
|
443
|
-
|
444
|
-
def wait_for_state state, timeout
|
500
|
+
def wait_for_state state, timeout:
|
445
501
|
states = [state].flatten
|
446
502
|
return if states.include?(@state)
|
447
|
-
|
503
|
+
wait_for_condition(@state_condition,timeout: timeout) do
|
448
504
|
states.include?(@state)
|
449
505
|
end
|
450
506
|
@state
|
451
|
-
rescue
|
507
|
+
rescue RSMP::TimeoutError
|
452
508
|
raise RSMP::TimeoutError.new "Did not reach state #{state} within #{timeout}s"
|
453
509
|
end
|
454
510
|
|
@@ -557,10 +613,10 @@ module RSMP
|
|
557
613
|
end
|
558
614
|
end
|
559
615
|
|
560
|
-
def
|
616
|
+
def handshake_complete
|
561
617
|
set_state :ready
|
562
618
|
end
|
563
|
-
|
619
|
+
|
564
620
|
def version_acknowledged
|
565
621
|
end
|
566
622
|
|
@@ -572,24 +628,11 @@ module RSMP
|
|
572
628
|
node.site_id
|
573
629
|
end
|
574
630
|
|
575
|
-
def wait_for_acknowledgement parent_task, options={}, m_id
|
576
|
-
collector = Collector.new self, options.merge(task: parent_task, type: ['MessageAck','MessageNotAck'])
|
577
|
-
collector.collect do |message|
|
578
|
-
if message.is_a?(MessageNotAck)
|
579
|
-
if message.attribute('oMId') == m_id
|
580
|
-
m_id_short = RSMP::Message.shorten_m_id m_id, 8
|
581
|
-
raise RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected with '#{message.attribute('rea')}'"
|
582
|
-
end
|
583
|
-
elsif message.is_a?(MessageAck)
|
584
|
-
collector.complete if message.attribute('oMId') == m_id
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end
|
588
|
-
|
589
631
|
def send_and_optionally_collect message, options, &block
|
590
632
|
collect_options = options[:collect] || options[:collect!]
|
591
633
|
if collect_options
|
592
634
|
task = @task.async do |task|
|
635
|
+
task.annotate 'send_and_optionally_collect'
|
593
636
|
collector = yield collect_options # call block to create collector
|
594
637
|
collector.collect
|
595
638
|
collector.ok! if options[:collect!] # raise any errors if the bang version was specified
|
data/lib/rsmp/rsmp.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Get the current time in UTC, with optional adjustment
|
2
|
-
# Convertion to string uses the RSMP format 2015-06-08T12:01:39.654Z
|
2
|
+
# Convertion to string uses the RSMP format 2015-06-08T12:01:39.654Z
|
3
3
|
# Note that using to_s on a my_clock.to_s will not produce an RSMP formatted timestamp,
|
4
4
|
# you need to use Clock.to_s my_clock
|
5
5
|
|
data/lib/rsmp/site.rb
CHANGED
@@ -15,6 +15,8 @@ module RSMP
|
|
15
15
|
@proxies = []
|
16
16
|
@sleep_condition = Async::Notification.new
|
17
17
|
@proxies_condition = Async::Notification.new
|
18
|
+
|
19
|
+
build_proxies
|
18
20
|
end
|
19
21
|
|
20
22
|
def site_id
|
@@ -62,25 +64,29 @@ module RSMP
|
|
62
64
|
RSMP::Schemer::find_schema! sxl, version, lenient: true
|
63
65
|
end
|
64
66
|
|
65
|
-
def
|
66
|
-
@
|
67
|
+
def run
|
68
|
+
log "Starting site #{@site_settings["site_id"]}",
|
69
|
+
level: :info,
|
70
|
+
timestamp: @clock.now
|
71
|
+
@proxies.each { |proxy| proxy.start }
|
72
|
+
@proxies.each { |proxy| proxy.wait }
|
67
73
|
end
|
68
74
|
|
69
|
-
def
|
75
|
+
def build_proxies
|
70
76
|
@site_settings["supervisors"].each do |supervisor_settings|
|
71
|
-
@
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
+
@proxies << SupervisorProxy.new({
|
78
|
+
site: self,
|
79
|
+
task: @task,
|
80
|
+
settings: @site_settings,
|
81
|
+
ip: supervisor_settings['ip'],
|
82
|
+
port: supervisor_settings['port'],
|
83
|
+
logger: @logger,
|
84
|
+
archive: @archive,
|
85
|
+
collect: @collect
|
86
|
+
})
|
77
87
|
end
|
78
88
|
end
|
79
89
|
|
80
|
-
def build_proxy settings
|
81
|
-
SupervisorProxy.new settings
|
82
|
-
end
|
83
|
-
|
84
90
|
def aggregated_status_changed component, options={}
|
85
91
|
@proxies.each do |proxy|
|
86
92
|
proxy.send_aggregated_status component, options if proxy.ready?
|
@@ -91,7 +97,7 @@ module RSMP
|
|
91
97
|
proxy = build_proxy({
|
92
98
|
site: self,
|
93
99
|
task: @task,
|
94
|
-
settings: @site_settings,
|
100
|
+
settings: @site_settings,
|
95
101
|
ip: supervisor_settings['ip'],
|
96
102
|
port: supervisor_settings['port'],
|
97
103
|
logger: @logger,
|
@@ -99,63 +105,20 @@ module RSMP
|
|
99
105
|
collect: @collect
|
100
106
|
})
|
101
107
|
@proxies << proxy
|
108
|
+
proxy.start
|
102
109
|
@proxies_condition.signal
|
103
|
-
run_site_proxy task, proxy
|
104
|
-
ensure
|
105
|
-
@proxies.delete proxy
|
106
|
-
@proxies_condition.signal
|
107
|
-
end
|
108
|
-
|
109
|
-
def run_site_proxy task, proxy
|
110
|
-
loop do
|
111
|
-
proxy.run # run until disconnected
|
112
|
-
rescue IOError => e
|
113
|
-
log "Stream error: #{e}", level: :warning
|
114
|
-
rescue StandardError => e
|
115
|
-
notify_error e, level: :internal
|
116
|
-
ensure
|
117
|
-
begin
|
118
|
-
if @site_settings['intervals']['watchdog'] != :no
|
119
|
-
# sleep until waken by reconnect() or the reconnect interval passed
|
120
|
-
proxy.set_state :wait_for_reconnect
|
121
|
-
task.with_timeout(@site_settings['intervals']['watchdog']) do
|
122
|
-
@sleep_condition.wait
|
123
|
-
end
|
124
|
-
else
|
125
|
-
proxy.set_state :cannot_connect
|
126
|
-
break
|
127
|
-
end
|
128
|
-
rescue Async::TimeoutError
|
129
|
-
# ignore
|
130
|
-
end
|
131
|
-
end
|
132
110
|
end
|
133
111
|
|
112
|
+
# stop
|
134
113
|
def stop
|
135
114
|
log "Stopping site #{@site_settings["site_id"]}", level: :info
|
136
|
-
@proxies.each do |proxy|
|
137
|
-
proxy.stop
|
138
|
-
end
|
139
|
-
@proxies.clear
|
140
115
|
super
|
141
116
|
end
|
142
|
-
|
143
|
-
def starting
|
144
|
-
log "Starting site #{@site_settings["site_id"]}",
|
145
|
-
level: :info,
|
146
|
-
timestamp: @clock.now
|
147
|
-
end
|
148
|
-
|
149
|
-
def alarm
|
150
|
-
@proxies.each do |proxy|
|
151
|
-
proxy.stop
|
152
|
-
end
|
153
|
-
end
|
154
117
|
|
155
118
|
def wait_for_supervisor ip, timeout
|
156
119
|
supervisor = find_supervisor ip
|
157
120
|
return supervisor if supervisor
|
158
|
-
|
121
|
+
wait_for_condition(@proxy_condition,timeout:timeout) { find_supervisor ip }
|
159
122
|
rescue Async::TimeoutError
|
160
123
|
raise RSMP::TimeoutError.new "Supervisor '#{ip}' did not connect within #{timeout}s"
|
161
124
|
end
|