require 'socket' class SocketServer def initialize(socket_path) @socket_path = socket_path @server = nil end def start(&blk) @server = UNIXServer.new(@socket_path) @accept_thread = new_accept_thread if blk @blk = blk end end def stop @server.close if @server @server = nil @blk = nil end protected def new_accept_thread server = @server Thread.new do done = false while !done done = !accept_connection(server) end end end def accept_connection(server) socket = nil begin socket = server.accept rescue IOError # socket was shut down or something catastrophic like that happened return false end start = Time.now line = "" while Time.now - start < 10 if IO.select([socket], nil, nil, 10) begin line << socket.read_nonblock(1000) rescue IO::WaitReadable sleep 0.001 end end break if line.include?("\n") end if line.include?("\n") socket.write get_response(line.strip) end true rescue IOError => e # nothing to do here, case its normal on shutdown rescue => e Rails.logger.warn("Failed to handle connection in stats socket #{e}") ensure socket&.close rescue nil end def get_response(command) if @blk @blk.call(command) else raise "Must be implemented by child" end end end