Skip to content

Instantly share code, notes, and snippets.

@darkphnx
Last active March 23, 2017 18:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darkphnx/12145a382d4c4eb15302e2d5a2d0eb20 to your computer and use it in GitHub Desktop.
Save darkphnx/12145a382d4c4eb15302e2d5a2d0eb20 to your computer and use it in GitHub Desktop.
Simple, hot-restartable Ruby service
require 'socket'
class SuperSimpleService
attr_reader :bind_address, :bind_port
def initialize
@bind_address = 'localhost'
@bind_port = 12345
end
def run
if ENV['SOCKET_FD']
@socket_server = TCPServer.for_fd(ENV['SOCKET_FD'].to_i)
kill_parent
else
@socket_server = TCPServer.new(bind_address, bind_port)
end
@socket_server.autoclose = false
@socket_server.close_on_exec = false
setup_signal_traps
loop do
begin
client_socket = @socket_server.accept # blocks until a new connection is made
@connection_active = true
client_socket.puts "Hello World!"
client_socket.close
ensure
@connection_active = false
end
end
end
def setup_signal_traps
trap('USR1') { hot_restart }
trap('TERM') { graceful_shutdown }
end
def hot_restart
fork do
# :close_others ensures that open file descriptors are inherited by the new process
exec("SOCKET_FD=#{@socket_server.fileno} ruby super_simple_service.rb", close_others: false)
end
end
def graceful_shutdown
@socket_server.close # Stop listening for new connections
sleep 0.1 while @connection_active # Wait for active connection to complete
Process.exit(0)
end
def kill_parent
parent_process_id = Process.ppid
Process.kill('TERM', parent_process_id)
end
end
SuperSimpleService.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment