uninterruptible 2.4.1 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/lib/uninterruptible/file_descriptor_server.rb +2 -2
- data/lib/uninterruptible/server.rb +43 -39
- data/lib/uninterruptible/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72a22a5770c97eab497ced8af3b4ef1eb1969954
|
4
|
+
data.tar.gz: 697a74b90a5f7f1e9fa0e4bd0c099e4565de8c4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35f6725ea1ed919a3ea884840bbd9462d26c451d1efa380a3c7b707427dae2be667b1eb2ffd006915b27371bcbfa897e04e2971b029fce0d72f7f7f32288ecc0
|
7
|
+
data.tar.gz: 2a0e883d4ebad0dab294743349d01d851f69e00d279746bdb6e4a35444893706b1ceb66223174685834ea14a380f8f7e436015c85a1415845760c3e1f099f2cc
|
data/CHANGELOG.md
CHANGED
@@ -16,7 +16,7 @@ module Uninterruptible
|
|
16
16
|
|
17
17
|
# @return [String] Location on disk where socket server is listening
|
18
18
|
def socket_path
|
19
|
-
@socket_path ||= File.join(socket_directory, '
|
19
|
+
@socket_path ||= File.join(socket_directory, 'fd.sock')
|
20
20
|
end
|
21
21
|
|
22
22
|
# Accept the next client connection and send it the file descriptor
|
@@ -41,7 +41,7 @@ module Uninterruptible
|
|
41
41
|
private
|
42
42
|
|
43
43
|
def socket_directory
|
44
|
-
@socket_directory ||= Dir.mktmpdir('
|
44
|
+
@socket_directory ||= Dir.mktmpdir('u-')
|
45
45
|
end
|
46
46
|
|
47
47
|
def start_socket_server
|
@@ -30,7 +30,7 @@ module Uninterruptible
|
|
30
30
|
module Server
|
31
31
|
def self.included(base)
|
32
32
|
base.class_eval do
|
33
|
-
attr_reader :active_connections, :socket_server, :signal_pipe_r, :signal_pipe_w, :mutex
|
33
|
+
attr_reader :active_connections, :socket_server, :signal_pipe_r, :signal_pipe_w, :mutex, :file_descriptor_server
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -52,9 +52,15 @@ module Uninterruptible
|
|
52
52
|
|
53
53
|
logger.info "Starting server on #{server_configuration.bind}"
|
54
54
|
|
55
|
-
|
55
|
+
# Set up each listener and add it to an array ready for the event loop
|
56
|
+
@active_descriptors = []
|
57
|
+
@active_descriptors << establish_socket_server
|
58
|
+
@active_descriptors << establish_file_descriptor_server
|
59
|
+
@active_descriptors << setup_signal_traps
|
60
|
+
|
56
61
|
write_pidfile
|
57
|
-
|
62
|
+
|
63
|
+
# Enter the main loop
|
58
64
|
select_loop
|
59
65
|
end
|
60
66
|
|
@@ -72,15 +78,31 @@ module Uninterruptible
|
|
72
78
|
# signal_pipe_r for processing any signals sent to the process.
|
73
79
|
def select_loop
|
74
80
|
loop do
|
75
|
-
|
76
|
-
readable.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
# Wait for descriptors or a 1 second timeout
|
82
|
+
readable, = IO.select(@active_descriptors, [], [], 1)
|
83
|
+
# Only process one descriptor per iteration.
|
84
|
+
# We don't want to process a descriptor that has been deleted.
|
85
|
+
reader = readable&.first
|
86
|
+
if reader == signal_pipe_r
|
87
|
+
signal = reader.gets.chomp
|
88
|
+
process_signal(signal)
|
89
|
+
elsif reader == file_descriptor_server.socket_server
|
90
|
+
file_descriptor_server.serve_file_descriptor
|
91
|
+
@active_descriptors.delete(file_descriptor_server.socket_server)
|
92
|
+
graceful_shutdown
|
93
|
+
elsif reader == socket_server
|
94
|
+
accept_client_connection
|
95
|
+
end
|
96
|
+
|
97
|
+
if @shutdown
|
98
|
+
if active_connections.zero?
|
99
|
+
logger.debug "No more active connections. Exiting'"
|
100
|
+
Process.exit(0)
|
101
|
+
else
|
102
|
+
logger.debug "#{active_connections} connections still active"
|
82
103
|
end
|
83
104
|
end
|
105
|
+
|
84
106
|
end
|
85
107
|
end
|
86
108
|
|
@@ -119,22 +141,18 @@ module Uninterruptible
|
|
119
141
|
# in the env, reconnect to that file descriptor.
|
120
142
|
def establish_socket_server
|
121
143
|
@socket_server = Uninterruptible::Binder.new(server_configuration.bind).bind_to_socket
|
122
|
-
# If there's a file descriptor present, take over from a previous instance of this server and kill it off
|
123
|
-
kill_parent if ENV[FILE_DESCRIPTOR_SERVER_VAR]
|
124
|
-
|
125
|
-
@socket_server.autoclose = false
|
126
|
-
@socket_server.close_on_exec = false
|
127
144
|
|
128
145
|
if server_configuration.tls_enabled?
|
129
146
|
@socket_server = Uninterruptible::TLSServerFactory.new(server_configuration).wrap_with_tls(@socket_server)
|
130
147
|
end
|
148
|
+
@socket_server
|
131
149
|
end
|
132
150
|
|
133
|
-
#
|
134
|
-
#
|
135
|
-
def
|
136
|
-
|
137
|
-
|
151
|
+
# Create the UNIX socket server that will pass the server file descriptor
|
152
|
+
# to the child process when a restart occurs.
|
153
|
+
def establish_file_descriptor_server
|
154
|
+
@file_descriptor_server = FileDescriptorServer.new(socket_server)
|
155
|
+
@file_descriptor_server.socket_server
|
138
156
|
end
|
139
157
|
|
140
158
|
# Write the current pid out to pidfile_path if configured
|
@@ -155,6 +173,7 @@ module Uninterruptible
|
|
155
173
|
@signal_pipe_w.puts(signal_name)
|
156
174
|
end
|
157
175
|
end
|
176
|
+
@signal_pipe_r
|
158
177
|
end
|
159
178
|
|
160
179
|
# When a signal has been caught, it should be passed here for the appropriate action to be taken
|
@@ -164,12 +183,11 @@ module Uninterruptible
|
|
164
183
|
# @param [String] signal_name Signal to process
|
165
184
|
def process_signal(signal_name)
|
166
185
|
if signal_name == 'TERM'
|
167
|
-
if
|
186
|
+
if @shutdown
|
168
187
|
logger.info "TERM received again, exiting immediately"
|
169
|
-
Process.exit(1)
|
188
|
+
Process.exit(1)
|
170
189
|
else
|
171
190
|
logger.info "TERM received, starting graceful shutdown"
|
172
|
-
$shutdown = true
|
173
191
|
graceful_shutdown
|
174
192
|
end
|
175
193
|
elsif signal_name == 'USR1'
|
@@ -181,22 +199,12 @@ module Uninterruptible
|
|
181
199
|
# Stop listening on socket_server, wait until all active connections have finished processing and exit with 0.
|
182
200
|
def graceful_shutdown
|
183
201
|
socket_server.close unless socket_server.closed?
|
184
|
-
|
185
|
-
|
186
|
-
logger.debug "#{active_connections} connections still active"
|
187
|
-
sleep 0.5
|
188
|
-
end
|
189
|
-
|
190
|
-
logger.debug "No more active connections. Exiting'"
|
191
|
-
|
192
|
-
Process.exit(0)
|
202
|
+
@active_descriptors.delete(socket_server)
|
203
|
+
@shutdown = true
|
193
204
|
end
|
194
205
|
|
195
206
|
# Start a new copy of this server, maintaining all current file descriptors and env.
|
196
207
|
def hot_restart
|
197
|
-
# Start a FileDescriptorServer running on a unix socket
|
198
|
-
file_descriptor_server = FileDescriptorServer.new(socket_server)
|
199
|
-
|
200
208
|
fork do
|
201
209
|
# Let the new server know where to find the file descriptor server
|
202
210
|
ENV[FILE_DESCRIPTOR_SERVER_VAR] = file_descriptor_server.socket_path
|
@@ -206,10 +214,6 @@ module Uninterruptible
|
|
206
214
|
|
207
215
|
exec("bundle exec #{server_configuration.start_command}")
|
208
216
|
end
|
209
|
-
|
210
|
-
# Provide the new server with the file descriptor for @socket_server
|
211
|
-
file_descriptor_server.serve_file_descriptor
|
212
|
-
file_descriptor_server.close
|
213
217
|
end
|
214
218
|
|
215
219
|
def network_restrictions
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uninterruptible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Wentworth
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|