forest_admin_rpc_agent 1.16.4 → 1.16.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 61c267e0f4478a14bb31888e27d27c667074664e3edc3f63d60e71d3a64b84d8
|
|
4
|
+
data.tar.gz: 8dcfa34e4f3be0c81434999b363036bd0806fc210a07f1f833fa643ce99b6efe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ed2f6d0a8470a07fd3ba641f4ec53ddf2ed2dab751bdeaed8cfa48a4a897891f61584c5e3117e7cc7acb0d56a04516758f5f3281f55d5ae50b2bc9872868ebe2
|
|
7
|
+
data.tar.gz: 6e69218d6db3390e6f86fd0c1ac39d9792bae33768fa4f42389ca09d82ec1eaa6c332de6423e483904340c56bfdc7d06fb8b8299d6910af5351b2dc153115dbb
|
|
@@ -3,7 +3,7 @@ require 'jsonapi-serializers'
|
|
|
3
3
|
module ForestAdminRpcAgent
|
|
4
4
|
module Routes
|
|
5
5
|
class Sse
|
|
6
|
-
DEFAULT_HEARTBEAT_INTERVAL =
|
|
6
|
+
DEFAULT_HEARTBEAT_INTERVAL = 10
|
|
7
7
|
|
|
8
8
|
def initialize(url = 'sse', method = 'get', name = 'rpc_sse', heartbeat_interval: DEFAULT_HEARTBEAT_INTERVAL)
|
|
9
9
|
@url = url
|
|
@@ -37,11 +37,13 @@ module ForestAdminRpcAgent
|
|
|
37
37
|
'X-Accel-Buffering' => 'no'
|
|
38
38
|
|
|
39
39
|
stream(:keep_open) do |out|
|
|
40
|
-
|
|
40
|
+
# Register this connection; any previous connection will be terminated
|
|
41
|
+
connection = ForestAdminRpcAgent::SseConnectionManager.register_connection
|
|
42
|
+
|
|
41
43
|
server_stopped = false
|
|
42
44
|
received_signal = nil
|
|
43
45
|
stop_proc = proc do |sig|
|
|
44
|
-
|
|
46
|
+
connection.terminate
|
|
45
47
|
server_stopped = true
|
|
46
48
|
received_signal = sig
|
|
47
49
|
end
|
|
@@ -51,7 +53,7 @@ module ForestAdminRpcAgent
|
|
|
51
53
|
begin
|
|
52
54
|
streamer = SseStreamer.new(out)
|
|
53
55
|
|
|
54
|
-
while
|
|
56
|
+
while connection.active?
|
|
55
57
|
streamer.write('', event: 'heartbeat')
|
|
56
58
|
sleep route_instance.instance_variable_get(:@heartbeat_interval)
|
|
57
59
|
end
|
|
@@ -71,6 +73,7 @@ module ForestAdminRpcAgent
|
|
|
71
73
|
ensure
|
|
72
74
|
trap('INT', original_int_handler)
|
|
73
75
|
trap('TERM', original_term_handler)
|
|
76
|
+
ForestAdminRpcAgent::SseConnectionManager.unregister_connection(connection)
|
|
74
77
|
out.close if out.respond_to?(:close)
|
|
75
78
|
|
|
76
79
|
# Re-send the signal to allow proper server shutdown
|
|
@@ -95,11 +98,13 @@ module ForestAdminRpcAgent
|
|
|
95
98
|
'X-Accel-Buffering' => 'no'
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
# Register this connection; any previous connection will be terminated
|
|
102
|
+
connection = ForestAdminRpcAgent::SseConnectionManager.register_connection
|
|
103
|
+
|
|
99
104
|
server_stopped = false
|
|
100
105
|
received_signal = nil
|
|
101
106
|
stop_proc = proc do |sig|
|
|
102
|
-
|
|
107
|
+
connection.terminate
|
|
103
108
|
server_stopped = true
|
|
104
109
|
received_signal = sig
|
|
105
110
|
end
|
|
@@ -112,7 +117,7 @@ module ForestAdminRpcAgent
|
|
|
112
117
|
begin
|
|
113
118
|
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] Starting stream')
|
|
114
119
|
|
|
115
|
-
while
|
|
120
|
+
while connection.active?
|
|
116
121
|
stream.write('', event: 'heartbeat')
|
|
117
122
|
sleep route_instance.instance_variable_get(:@heartbeat_interval)
|
|
118
123
|
end
|
|
@@ -135,6 +140,7 @@ module ForestAdminRpcAgent
|
|
|
135
140
|
ensure
|
|
136
141
|
trap('INT', original_int_handler)
|
|
137
142
|
trap('TERM', original_term_handler)
|
|
143
|
+
ForestAdminRpcAgent::SseConnectionManager.unregister_connection(connection)
|
|
138
144
|
ForestAdminRpcAgent::Facades::Container.logger&.log('Debug', '[SSE] Stream stopped')
|
|
139
145
|
|
|
140
146
|
# Re-send the signal to allow proper server shutdown
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module ForestAdminRpcAgent
|
|
2
|
+
# Manages SSE connections to ensure only one active connection at a time.
|
|
3
|
+
# When a new connection is established, the previous one is terminated.
|
|
4
|
+
# This prevents zombie loops when the master restarts and reconnects.
|
|
5
|
+
class SseConnectionManager
|
|
6
|
+
@mutex = Mutex.new
|
|
7
|
+
@current_connection = nil
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Registers a new SSE connection and terminates any existing one.
|
|
11
|
+
# Returns a connection object that can be used to check if the connection is still active.
|
|
12
|
+
def register_connection
|
|
13
|
+
connection = Connection.new
|
|
14
|
+
|
|
15
|
+
@mutex.synchronize do
|
|
16
|
+
# Terminate the previous connection if it exists
|
|
17
|
+
if @current_connection
|
|
18
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log(
|
|
19
|
+
'Debug',
|
|
20
|
+
'[SSE ConnectionManager] Terminating previous connection'
|
|
21
|
+
)
|
|
22
|
+
@current_connection.terminate
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@current_connection = connection
|
|
26
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log(
|
|
27
|
+
'Debug',
|
|
28
|
+
"[SSE ConnectionManager] New connection registered (id: #{connection.id})"
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
connection
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Unregisters a connection when it's closed normally.
|
|
36
|
+
def unregister_connection(connection)
|
|
37
|
+
@mutex.synchronize do
|
|
38
|
+
if @current_connection&.id == connection.id
|
|
39
|
+
@current_connection = nil
|
|
40
|
+
ForestAdminRpcAgent::Facades::Container.logger&.log(
|
|
41
|
+
'Debug',
|
|
42
|
+
"[SSE ConnectionManager] Connection unregistered (id: #{connection.id})"
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the current active connection (for testing purposes)
|
|
49
|
+
def current_connection
|
|
50
|
+
@mutex.synchronize { @current_connection }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Resets the manager state (for testing purposes)
|
|
54
|
+
def reset!
|
|
55
|
+
@mutex.synchronize do
|
|
56
|
+
@current_connection&.terminate
|
|
57
|
+
@current_connection = nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Represents an individual SSE connection
|
|
63
|
+
class Connection
|
|
64
|
+
attr_reader :id
|
|
65
|
+
|
|
66
|
+
def initialize
|
|
67
|
+
@id = SecureRandom.uuid
|
|
68
|
+
@active = true
|
|
69
|
+
@mutex = Mutex.new
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def active?
|
|
73
|
+
@mutex.synchronize { @active }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def terminate
|
|
77
|
+
@mutex.synchronize { @active = false }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_admin_rpc_agent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.16.
|
|
4
|
+
version: 1.16.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthieu
|
|
@@ -178,6 +178,7 @@ files:
|
|
|
178
178
|
- lib/forest_admin_rpc_agent/routes/schema.rb
|
|
179
179
|
- lib/forest_admin_rpc_agent/routes/sse.rb
|
|
180
180
|
- lib/forest_admin_rpc_agent/routes/update.rb
|
|
181
|
+
- lib/forest_admin_rpc_agent/sse_connection_manager.rb
|
|
181
182
|
- lib/forest_admin_rpc_agent/sse_streamer.rb
|
|
182
183
|
- lib/forest_admin_rpc_agent/thor/install.rb
|
|
183
184
|
- lib/forest_admin_rpc_agent/version.rb
|