uninterruptible 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 658c5837ae17777ac2f5d53223b61941444c26ca
4
- data.tar.gz: db14a041c27690a14565f5938255856b1bfde528
3
+ metadata.gz: 6c0bee80d95f929271d75f691c59788a9716e8e3
4
+ data.tar.gz: 877066cf757d14caab769f7585713170f7db08e2
5
5
  SHA512:
6
- metadata.gz: 5421a7627be91b402d0189ae4791dbcce3c5a2d259ffbcaaa3177a4e577d18d1b7a384a86d700dcdf8ae493e872516593f25b4f83daea6dc020a5ea24b847417
7
- data.tar.gz: 214ded520ee70b7c87fbf8ed9efaf139803830db02d294189a56d9c9f0ecc76277159599ac950abb1338642e300d38bcf9c624327563364e7ff4c9106fa9dd7e
6
+ metadata.gz: 2f2f1edad24e0bad293acb8f70a3171388c98d73f266f025c570ed58fda332d47cf0f95c00cfd1f8b293b142b4d8882b496201daa5da30beada562363b8999df
7
+ data.tar.gz: 775f0729644939e948a87adb085105651a00500793d6db9b19b5965faf008f5bea4dbab21fb279bd030604f134c177530c65db64ea37530c4bf3f9f23ecfa543
data/CHANGELOG.md CHANGED
@@ -1,22 +1,25 @@
1
1
  # Changelog
2
2
 
3
- # 2.3.0
3
+ ## 2.4.0
4
+ * When restarting a server, the socket is passed to the new server via a UNIX socket instead of inheriting open file descriptors from the parent.
5
+
6
+ ## 2.3.0
4
7
  * Incoming connections can be restricted to certain networks by setting `allowed_networks` in the configuration.
5
8
 
6
- # 2.2.1
9
+ ## 2.2.1
7
10
  * Allow multiple certificates to be used in one build file
8
11
 
9
- # 2.2.0
12
+ ## 2.2.0
10
13
  * Verify client TLS certificates
11
14
  * Allow trusted client CA to be set
12
15
 
13
- # 2.1.1
16
+ ## 2.1.1
14
17
  * Prevent bad SSL handshakes from crashing server
15
18
 
16
- # 2.1.0
19
+ ## 2.1.0
17
20
  * Add TLS support for TCP connections
18
21
 
19
- # 2.0.0
22
+ ## 2.0.0
20
23
  * Use an internal pipe for delivering signals to the main thread.
21
24
  * `accept_connections` retired in favour of a select loop and `accept_client_connection` being called for each waiting connection
22
25
  * Logging when shutting down or restarting
@@ -34,8 +34,8 @@ module Uninterruptible
34
34
  #
35
35
  # @return [TCPServer] Socket server for the configured address and port
36
36
  def bind_to_tcp_socket
37
- if ENV[SERVER_FD_VAR]
38
- TCPServer.for_fd(ENV[SERVER_FD_VAR].to_i)
37
+ if ENV[FILE_DESCRIPTOR_SERVER_VAR]
38
+ TCPServer.for_fd(read_file_descriptor_from_fds)
39
39
  else
40
40
  TCPServer.new(bind_uri.host, bind_uri.port)
41
41
  end
@@ -45,14 +45,16 @@ module Uninterruptible
45
45
  #
46
46
  # @return [UNIXServer] Socket server for the configured path
47
47
  def bind_to_unix_socket
48
- if ENV[SERVER_FD_VAR]
49
- UNIXServer.for_fd(ENV[SERVER_FD_VAR].to_i)
48
+ if ENV[FILE_DESCRIPTOR_SERVER_VAR]
49
+ UNIXServer.for_fd(read_file_descriptor_from_fds)
50
50
  else
51
51
  File.delete(bind_uri.path) if File.exist?(bind_uri.path)
52
52
  UNIXServer.new(bind_uri.path)
53
53
  end
54
54
  end
55
55
 
56
+ private
57
+
56
58
  # Parse the bind address in the configuration
57
59
  #
58
60
  # @param [String] bind_address The config for a server we're returning the socket for
@@ -65,5 +67,14 @@ module Uninterruptible
65
67
  rescue URI::Error
66
68
  raise Uninterruptible::ConfigurationError, "Couldn't parse the bind address: \"#{bind_address}\""
67
69
  end
70
+
71
+ # Open a connection to a running FileDesciptorServer on the parent of this server and obtain a file descriptor
72
+ # for the running socket server on there.
73
+ def read_file_descriptor_from_fds
74
+ fds_socket = UNIXSocket.new(ENV[FILE_DESCRIPTOR_SERVER_VAR])
75
+ socket_file_descriptor = fds_socket.recv_io
76
+ fds_socket.close
77
+ socket_file_descriptor.to_i
78
+ end
68
79
  end
69
80
  end
@@ -0,0 +1,51 @@
1
+ require 'tmpdir'
2
+ require 'socket'
3
+
4
+ module Uninterruptible
5
+ class FileDescriptorServer
6
+ attr_reader :io_object, :socket_server
7
+
8
+ # Creates a new FileDescriptorServer and starts a listenting socket server
9
+ #
10
+ # @param [IO] Any IO object that will be shared by this server
11
+ def initialize(io_object)
12
+ @io_object = io_object
13
+
14
+ start_socket_server
15
+ end
16
+
17
+ # @return [String] Location on disk where socket server is listening
18
+ def socket_path
19
+ @socket_path ||= File.join(socket_directory, 'file_descriptor_server.sock')
20
+ end
21
+
22
+ # Accept the next client connection and send it the file descriptor
23
+ #
24
+ # @raise [RuntimeError] Raises a runtime error if the socket server is closed
25
+ def serve_file_descriptor
26
+ raise "File descriptor server has been closed" if socket_server.closed?
27
+
28
+ client = socket_server.accept
29
+ client.send_io(io_object)
30
+ client.close
31
+ end
32
+
33
+ # Close the socket server and tidy up any created files
34
+ def close
35
+ socket_server.close
36
+
37
+ File.delete(socket_path)
38
+ Dir.rmdir(socket_directory)
39
+ end
40
+
41
+ private
42
+
43
+ def socket_directory
44
+ @socket_directory ||= Dir.mktmpdir('uninterruptible-')
45
+ end
46
+
47
+ def start_socket_server
48
+ @socket_server = UNIXServer.new(socket_path)
49
+ end
50
+ end
51
+ end
@@ -113,12 +113,12 @@ module Uninterruptible
113
113
  end
114
114
  end
115
115
 
116
- # Listen (or reconnect) to the bind address and port specified in the config. If SERVER_FD_VAR is set in the env,
117
- # reconnect to that file descriptor. Once @socket_server is set, write the file descriptor ID to the env.
116
+ # Listen (or reconnect) to the bind address and port specified in the config. If FILE_DESCRIPTOR_SERVER_PATH is set
117
+ # in the env, reconnect to that file descriptor.
118
118
  def establish_socket_server
119
119
  @socket_server = Uninterruptible::Binder.new(server_configuration.bind).bind_to_socket
120
120
  # If there's a file descriptor present, take over from a previous instance of this server and kill it off
121
- kill_parent if ENV[SERVER_FD_VAR]
121
+ kill_parent if ENV[FILE_DESCRIPTOR_SERVER_VAR]
122
122
 
123
123
  @socket_server.autoclose = false
124
124
  @socket_server.close_on_exec = false
@@ -126,8 +126,6 @@ module Uninterruptible
126
126
  if server_configuration.tls_enabled?
127
127
  @socket_server = Uninterruptible::TLSServerFactory.new(server_configuration).wrap_with_tls(@socket_server)
128
128
  end
129
-
130
- ENV[SERVER_FD_VAR] = @socket_server.to_i.to_s
131
129
  end
132
130
 
133
131
  # Send a TERM signal to the parent process. This will be called by a newly spawned server if it has been started
@@ -194,11 +192,22 @@ module Uninterruptible
194
192
 
195
193
  # Start a new copy of this server, maintaining all current file descriptors and env.
196
194
  def hot_restart
195
+ # Start a FileDescriptorServer running on a unix socket
196
+ file_descriptor_server = FileDescriptorServer.new(socket_server)
197
+
197
198
  fork do
199
+ # Let the new server know where to find the file descriptor server
200
+ ENV[FILE_DESCRIPTOR_SERVER_VAR] = file_descriptor_server.socket_path
201
+
198
202
  Dir.chdir(ENV['APP_ROOT']) if ENV['APP_ROOT']
199
203
  ENV.delete('BUNDLE_GEMFILE') # Ensure a fresh bundle is used
200
- exec("bundle exec --keep-file-descriptors #{server_configuration.start_command}", :close_others => false)
204
+
205
+ exec("bundle exec #{server_configuration.start_command}")
201
206
  end
207
+
208
+ # Provide the new server with the file descriptor for @socket_server
209
+ file_descriptor_server.serve_file_descriptor
210
+ file_descriptor_server.close
202
211
  end
203
212
 
204
213
  def network_restrictions
@@ -1,3 +1,3 @@
1
1
  module Uninterruptible
2
- VERSION = "2.3.1".freeze
2
+ VERSION = "2.4.0".freeze
3
3
  end
@@ -5,6 +5,7 @@ require "uninterruptible/version"
5
5
  require 'uninterruptible/ssl_extensions'
6
6
  require 'uninterruptible/configuration'
7
7
  require 'uninterruptible/binder'
8
+ require 'uninterruptible/file_descriptor_server'
8
9
  require 'uninterruptible/network_restrictions'
9
10
  require 'uninterruptible/tls_server_factory'
10
11
  require 'uninterruptible/server'
@@ -13,5 +14,5 @@ require 'uninterruptible/server'
13
14
  module Uninterruptible
14
15
  class ConfigurationError < StandardError; end
15
16
 
16
- SERVER_FD_VAR = 'UNINTERRUPTIBLE_SERVER_FD'.freeze
17
+ FILE_DESCRIPTOR_SERVER_VAR = 'FILE_DESCRIPTOR_SERVER_PATH'.freeze
17
18
  end
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.3.1
4
+ version: 2.4.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: 2018-03-19 00:00:00.000000000 Z
11
+ date: 2019-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,6 +75,7 @@ files:
75
75
  - lib/uninterruptible.rb
76
76
  - lib/uninterruptible/binder.rb
77
77
  - lib/uninterruptible/configuration.rb
78
+ - lib/uninterruptible/file_descriptor_server.rb
78
79
  - lib/uninterruptible/network_restrictions.rb
79
80
  - lib/uninterruptible/server.rb
80
81
  - lib/uninterruptible/ssl_extensions.rb
@@ -101,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
102
  version: '0'
102
103
  requirements: []
103
104
  rubyforge_project:
104
- rubygems_version: 2.5.2.1
105
+ rubygems_version: 2.6.14.3
105
106
  signing_key:
106
107
  specification_version: 4
107
108
  summary: Zero-downtime restarts for your trivial socket servers