nonnative 3.34.0 → 3.35.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 +4 -4
- data/README.md +5 -3
- data/lib/nonnative/fault_injection_proxy.rb +35 -5
- data/lib/nonnative/pool.rb +1 -1
- data/lib/nonnative/timeout.rb +4 -1
- data/lib/nonnative/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9a3ed94a590e8273136387f186364d01270536a472d476fc806b8e9d1d06c07
|
|
4
|
+
data.tar.gz: 9b1b14eb944a13c83c93bf816d4b485d0f1818080167a6f5339c7bba73d59c31
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 370d1071e0665f5ea99a06a5dcf4fbe18224aee3d47b9f4279f3fd881c03340869fc11b1b8a58349065bae3d98ffa7be5243a34c26351366b53063676a7cb859
|
|
7
|
+
data.tar.gz: 94ad2439c76e863ee3b6a34655454e0610f3a7f8c0b5db23df9af0c0bfc54924ca63410008eccf4b261b6693f601c0495d2bc668bce5a96f9a5a319db44088da
|
data/README.md
CHANGED
|
@@ -79,6 +79,7 @@ Process/server fields:
|
|
|
79
79
|
- `ports`: client-facing ports. These are also used for readiness/shutdown port checks.
|
|
80
80
|
- `timeout`: max time (seconds) for each readiness/shutdown check. For processes, the same value also
|
|
81
81
|
bounds optional HTTP/gRPC probes and graceful child exit after the stop signal. Defaults to `1.0`.
|
|
82
|
+
A value of `0` fails immediately; setting it to `nil` programmatically does the same.
|
|
82
83
|
- `wait`: small sleep (seconds) between lifecycle steps.
|
|
83
84
|
- `log`: per-runner log file used by process output redirection or server implementations.
|
|
84
85
|
|
|
@@ -89,7 +90,8 @@ Process-only fields:
|
|
|
89
90
|
|
|
90
91
|
Service fields:
|
|
91
92
|
- `port`: client-facing service port.
|
|
92
|
-
- `timeout`: max time (seconds) for opt-in service readiness checks. Defaults to `1.0`.
|
|
93
|
+
- `timeout`: max time (seconds) for opt-in service readiness checks. Defaults to `1.0`. A value of
|
|
94
|
+
`0` fails immediately; setting it to `nil` programmatically does the same.
|
|
93
95
|
- `readiness`: optional list of startup readiness checks. Supported kind is `tcp`, which requires
|
|
94
96
|
explicit `host` and `port`.
|
|
95
97
|
|
|
@@ -114,8 +116,8 @@ Nonnative.stop
|
|
|
114
116
|
|
|
115
117
|
`Nonnative.start` runs ordered tiers: service lifecycle calls and optional readiness checks complete,
|
|
116
118
|
then server lifecycle and readiness checks complete, then process lifecycle and readiness checks run.
|
|
117
|
-
A failed service readiness check prevents later tiers; other collected startup errors
|
|
118
|
-
after the attempted tiers finish. `Nonnative.stop` reverses the tiers: processes, servers, then
|
|
119
|
+
A failed service lifecycle call or readiness check prevents later tiers; other collected startup errors
|
|
120
|
+
trigger rollback after the attempted tiers finish. `Nonnative.stop` reverses the tiers: processes, servers, then
|
|
119
121
|
services. Model dependencies in that direction; a managed server can satisfy a process dependency,
|
|
120
122
|
but a server cannot wait on a managed process. Startup failures raise `Nonnative::StartError`, and
|
|
121
123
|
shutdown failures raise `Nonnative::StopError`.
|
|
@@ -52,6 +52,8 @@ module Nonnative
|
|
|
52
52
|
# @see Nonnative::Proxy
|
|
53
53
|
# @see Nonnative::SocketPairFactory
|
|
54
54
|
class FaultInjectionProxy < Nonnative::Proxy
|
|
55
|
+
STOP_DRAIN_TIMEOUT = 1
|
|
56
|
+
|
|
55
57
|
class Connection
|
|
56
58
|
attr_accessor :pair, :thread
|
|
57
59
|
attr_reader :socket
|
|
@@ -73,6 +75,7 @@ module Nonnative
|
|
|
73
75
|
@logger = Logger.new(service.proxy.log)
|
|
74
76
|
@mutex = Mutex.new
|
|
75
77
|
@state = :none
|
|
78
|
+
@stopping = false
|
|
76
79
|
|
|
77
80
|
super
|
|
78
81
|
end
|
|
@@ -84,6 +87,7 @@ module Nonnative
|
|
|
84
87
|
#
|
|
85
88
|
# @return [void]
|
|
86
89
|
def start
|
|
90
|
+
mutex.synchronize { @stopping = false }
|
|
87
91
|
@tcp_server = ::TCPServer.new(service.host, service.port)
|
|
88
92
|
@thread = Thread.new { perform_start }
|
|
89
93
|
|
|
@@ -95,6 +99,9 @@ module Nonnative
|
|
|
95
99
|
# @return [void]
|
|
96
100
|
def stop
|
|
97
101
|
server = tcp_server
|
|
102
|
+
mark_stopping
|
|
103
|
+
close_connections
|
|
104
|
+
close_queued_connections(server)
|
|
98
105
|
server&.close
|
|
99
106
|
|
|
100
107
|
listener_thread = thread
|
|
@@ -107,8 +114,6 @@ module Nonnative
|
|
|
107
114
|
@tcp_server = nil
|
|
108
115
|
@thread = nil
|
|
109
116
|
|
|
110
|
-
close_connections
|
|
111
|
-
|
|
112
117
|
Nonnative.logger.info "stopped with host '#{service.host}' and port '#{service.port}' for proxy 'fault_injection'"
|
|
113
118
|
end
|
|
114
119
|
|
|
@@ -225,13 +230,16 @@ module Nonnative
|
|
|
225
230
|
|
|
226
231
|
private
|
|
227
232
|
|
|
228
|
-
attr_reader :tcp_server, :thread, :connections, :mutex, :state, :logger
|
|
233
|
+
attr_reader :tcp_server, :thread, :connections, :mutex, :state, :logger, :stopping
|
|
229
234
|
|
|
230
235
|
def perform_start
|
|
231
236
|
loop do
|
|
232
237
|
local_socket = tcp_server.accept
|
|
233
238
|
id = local_socket.object_id
|
|
234
|
-
register_connection(id, local_socket)
|
|
239
|
+
unless register_connection(id, local_socket)
|
|
240
|
+
local_socket.close
|
|
241
|
+
next
|
|
242
|
+
end
|
|
235
243
|
connection_thread = Thread.start(local_socket) do |accepted_socket|
|
|
236
244
|
accept_connection id, accepted_socket
|
|
237
245
|
end
|
|
@@ -275,6 +283,19 @@ module Nonnative
|
|
|
275
283
|
end
|
|
276
284
|
end
|
|
277
285
|
|
|
286
|
+
def close_queued_connections(server)
|
|
287
|
+
return unless server
|
|
288
|
+
|
|
289
|
+
# This connection is queued after every client that connected before shutdown began.
|
|
290
|
+
# When the listener accepts and closes it, those earlier clients have been closed as well.
|
|
291
|
+
barrier = TCPSocket.new(service.host, service.port)
|
|
292
|
+
barrier.wait_readable(STOP_DRAIN_TIMEOUT)
|
|
293
|
+
rescue IOError, SystemCallError
|
|
294
|
+
nil
|
|
295
|
+
ensure
|
|
296
|
+
barrier&.close
|
|
297
|
+
end
|
|
298
|
+
|
|
278
299
|
def apply_state(state)
|
|
279
300
|
Nonnative.logger.info "applying state '#{state}' for proxy 'fault_injection'"
|
|
280
301
|
|
|
@@ -293,7 +314,16 @@ module Nonnative
|
|
|
293
314
|
end
|
|
294
315
|
|
|
295
316
|
def register_connection(id, socket)
|
|
296
|
-
mutex.synchronize
|
|
317
|
+
mutex.synchronize do
|
|
318
|
+
return false if stopping
|
|
319
|
+
|
|
320
|
+
connections[id] = Connection.new(socket)
|
|
321
|
+
true
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def mark_stopping
|
|
326
|
+
mutex.synchronize { @stopping = true }
|
|
297
327
|
end
|
|
298
328
|
|
|
299
329
|
def attach_connection_thread(id, thread)
|
data/lib/nonnative/pool.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Nonnative
|
|
|
37
37
|
errors.concat(service_lifecycle(services, :start, :start))
|
|
38
38
|
service_readiness_errors = check_service_readiness(services)
|
|
39
39
|
errors.concat(service_readiness_errors)
|
|
40
|
-
return errors if
|
|
40
|
+
return errors if errors.any?
|
|
41
41
|
|
|
42
42
|
[servers, processes].each { |runners| errors.concat(run_lifecycle_checks(runners, :start, :open?, :start)) }
|
|
43
43
|
|
data/lib/nonnative/timeout.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Nonnative
|
|
|
15
15
|
# # ok is either the block result or false if the timeout elapsed
|
|
16
16
|
#
|
|
17
17
|
class Timeout
|
|
18
|
-
# @param time [Numeric] timeout duration in seconds
|
|
18
|
+
# @param time [Numeric, nil] timeout duration in seconds; zero and `nil` values time out immediately
|
|
19
19
|
def initialize(time)
|
|
20
20
|
@time = time
|
|
21
21
|
end
|
|
@@ -23,10 +23,13 @@ module Nonnative
|
|
|
23
23
|
# Executes the given block with the configured timeout.
|
|
24
24
|
#
|
|
25
25
|
# If the timeout elapses, returns `false` instead of raising `Timeout::Error`.
|
|
26
|
+
# Zero and `nil` durations also return `false` without running the block.
|
|
26
27
|
#
|
|
27
28
|
# @yield the work to execute under a timeout
|
|
28
29
|
# @return [Object, false] the block's return value, or `false` if the timeout elapsed
|
|
29
30
|
def perform(&)
|
|
31
|
+
return false if time.nil? || time.zero?
|
|
32
|
+
|
|
30
33
|
::Timeout.timeout(time, &)
|
|
31
34
|
rescue ::Timeout::Error
|
|
32
35
|
false
|
data/lib/nonnative/version.rb
CHANGED