# frozen_string_literal: true require 'fileutils' module Legion # Responsible for starting the Legion process class Process def self.run!(options) Legion::Process.new(options).run! end attr_reader :options, :quit, :service def initialize(options) @options = options options[:logfile] = File.expand_path(logfile) if logfile? options[:pidfile] = File.expand_path(pidfile) if pidfile? end def daemonize? options[:daemonize] end def logfile options[:logfile] end def pidfile options[:pidfile] end def logfile? !logfile.nil? end def pidfile? !pidfile.nil? end def info(msg) puts "[#{::Process.pid}] [#{Time.now}] #{msg}" end def run! check_pid daemonize if daemonize? write_pid trap_signals until quit sleep(1) # in real life, something productive would happen here end # sleep(1) # sleep(1) Legion::Logging.info('Legion is shutting down!') # @service.shutdown Legion::Logging.info('Legion has shutdown. Goodbye!') exit end #========================================================================== # DAEMONIZING, PID MANAGEMENT, and OUTPUT REDIRECTION #========================================================================== def daemonize exit if fork ::Process.setsid exit if fork Dir.chdir '/' end def write_pid if pidfile? begin File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY) { |f| f.write(::Process.pid.to_s) } at_exit { File.delete(pidfile) if File.exist?(pidfile) } rescue Errno::EEXIST check_pid retry end end false end def check_pid if pidfile? case pid_status(pidfile) when :running, :not_owned exit(1) when :dead File.delete(pidfile) end end false end def pid_status(pidfile) return :exited unless File.exist?(pidfile) pid = ::File.read(pidfile).to_i return :dead if pid.zero? ::Process.kill(0, pid) :running rescue Errno::ESRCH :dead rescue Errno::EPERM :not_owned end #========================================================================== # SIGNAL HANDLING #========================================================================== def trap_signals # trap(:QUIT) do # graceful shutdown # info 'shutting down' # @quit = true # end trap('SIGTERM') do info 'sigterm' end trap('SIGHUP') do info 'sithup' end trap('SIGINT') do @quit = true end end end end