Class: Pidly::Control

Inherits:
Object
  • Object
show all
Includes:
Callbacks, Logger
Defined in:
lib/pidly/control.rb

Overview

Pidly daemon control

Instance Attribute Summary collapse

Attributes included from Logger

#verbosity

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logger

included, #log, #verbose?

Methods included from Callbacks

#add_callback, #after_stop, #before_start, #error, included

Constructor Details

#initialize(options = {}) ⇒ Control

Initialize control object

Parameters:

  • options (Hash) (defaults to: {})

    The options to create a controller with.

Raises:

  • (RuntimeError)

    Raise exception if path does not exist

  • (RuntimeError)

    Raise exception if path is not readable or writable.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/pidly/control.rb', line 38

def initialize(options={})

  @messages = []

  @error_count = 0

  @name = options.fetch(:name)

  if options.has_key?(:path)
    @path = Pathname.new(options.fetch(:path))
  else
    @path = Pathname.new('/tmp')
  end

  unless @path.directory?
    raise('Path does not exist or is not a directory.')
  end

  unless @path.readable? && @path.writable?
    raise('Path must be readable and writable.')
  end

  if options.has_key?(:pid_file)
    @pid_file = options.fetch(:pid_path)
  else
    @pid_file = File.join(@path.to_s, 'pids', @name + '.pid')
  end

  if options.has_key?(:log_file)
    @log_file = options.fetch(:log_path)
  else
    @log_file = File.join(@path.to_s, 'logs', @name + '.log')
  end

  @pid = fetch_pid if File.file?(@pid_file)

  @sync_log = options.fetch(:sync_log, true)

  @allow_multiple = options.fetch(:allow_multiple, false)

  @signal = options.fetch(:signal, "TERM")

  @timeout = options.fetch(:timeout, 10)

  @verbosity = options.fetch(:verbose, false)

  @logger = options.fetch(:logger, true)
end

Instance Attribute Details

#allow_multipleObject

Returns the value of attribute allow_multiple.



23
24
25
# File 'lib/pidly/control.rb', line 23

def allow_multiple
  @allow_multiple
end

#daemonObject

Returns the value of attribute daemon.



23
24
25
# File 'lib/pidly/control.rb', line 23

def daemon
  @daemon
end

#error_countObject

Returns the value of attribute error_count.



23
24
25
# File 'lib/pidly/control.rb', line 23

def error_count
  @error_count
end

#log_fileObject

Returns the value of attribute log_file.



23
24
25
# File 'lib/pidly/control.rb', line 23

def log_file
  @log_file
end

#messagesObject

Returns the value of attribute messages.



23
24
25
# File 'lib/pidly/control.rb', line 23

def messages
  @messages
end

#nameObject

Returns the value of attribute name.



23
24
25
# File 'lib/pidly/control.rb', line 23

def name
  @name
end

#pathObject

Returns the value of attribute path.



23
24
25
# File 'lib/pidly/control.rb', line 23

def path
  @path
end

#pidObject

Returns the value of attribute pid.



23
24
25
# File 'lib/pidly/control.rb', line 23

def pid
  @pid
end

#pid_fileObject

Returns the value of attribute pid_file.



23
24
25
# File 'lib/pidly/control.rb', line 23

def pid_file
  @pid_file
end

#sync_logObject

Returns the value of attribute sync_log.



23
24
25
# File 'lib/pidly/control.rb', line 23

def sync_log
  @sync_log
end

#timeoutObject

Returns the value of attribute timeout.



23
24
25
# File 'lib/pidly/control.rb', line 23

def timeout
  @timeout
end

#verboseObject

Returns the value of attribute verbose.



23
24
25
# File 'lib/pidly/control.rb', line 23

def verbose
  @verbose
end

Class Method Details

.spawn(options = {}) ⇒ Control

Spawn

Parameters:

  • options (Hash) (defaults to: {})

    The options to create a controller with.

Options Hash (options):

  • :name (String)

    Daemon name

  • :path (String)

    Path to create the log/pids directory

  • :pid_file (String)

    Pid file path

  • :log_file (String)

    Log file path

  • :sync_log (true, false)

    Synchronize log files

  • :allow_multiple (true, false)

    Allow multiple daemons of the same type

  • :sync_log (true, false)

    Synchronize log files

  • :signal (String)

    Trap signal

  • :timeout (Integer)

    Timeout for Process#wait

  • :verbose (true, false)

    Display daemon messages

  • :logger (true, false)

    Enable daemon logging

Returns:



117
118
119
# File 'lib/pidly/control.rb', line 117

def self.spawn(options={})
  @daemon = new(options)
end

Instance Method Details

#kill(remove_pid_file = true) ⇒ Object

Kill

Parameters:

  • remove_pid_file (String) (defaults to: true)

    Remove the daemon pid file



249
250
251
252
253
254
255
256
257
# File 'lib/pidly/control.rb', line 249

def kill(remove_pid_file=true)
  if running?
    log(:info, "Killing #{@name} (PID #{@pid})")
    Process.kill 9, @pid
  end

  FileUtils.rm(@pid_file) if remove_pid_file
rescue Errno::ENOENT
end

#restartObject

Restart

Restart the daemon



240
241
242
# File 'lib/pidly/control.rb', line 240

def restart
  stop; sleep 1 while running?; start
end

#running?true, false

Running?

Returns:

  • (true, false)

    Return the running status of the daemon.



264
265
266
267
268
269
270
271
272
273
# File 'lib/pidly/control.rb', line 264

def running?
  Process.kill 0, @pid
  true
rescue Errno::ESRCH
  false
rescue Errno::EPERM
  true
rescue
  false
end

#startObject

Start

Validate callbacks and start daemon



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/pidly/control.rb', line 126

def start
  validate_files_and_paths!
  validate_callbacks!

  unless @allow_multiple
    if running?
      log(:error, "#{@name} is already running (PID #{@pid})")
      return
    end
  end

  @pid = fork do
    begin
      Process.setsid

      open(@pid_file, 'w') do |f|
        f << Process.pid
        @pid = Process.pid
      end

      execute_callback(:before_start)

      Dir.chdir @path.to_s
      File.umask 0000

      if @logger
        log = File.new(@log_file, "a")
        log.sync = @sync_log

        STDIN.reopen "/dev/null"
        STDOUT.reopen log
        STDERR.reopen STDOUT
      end
      
      trap("TERM") do
        stop
      end

      execute_callback(:start)

    rescue RuntimeError => message
      STDERR.puts message
      STDERR.puts message.backtrace

      execute_callback(:error)
    rescue => message
      STDERR.puts message
      STDERR.puts message.backtrace

      execute_callback(:error)
    end
  end

rescue => message
  STDERR.puts message
  STDERR.puts message.backtrace
  execute_callback(:error)
end

#statusString

Status

Return current daemon status and pid

Returns:

  • (String)

    Status



227
228
229
230
231
232
233
# File 'lib/pidly/control.rb', line 227

def status
  if running?
    log(:info, "#{@name} is running (PID #{@pid})")
  else
    log(:info, "#{@name} is NOT running")
  end
end

#stopObject

Stop

Stop daemon and remove pid file



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/pidly/control.rb', line 190

def stop

  if running?

    Process.kill(@signal, @pid)
    FileUtils.rm(@pid_file)

    execute_callback(:stop)

    begin
      Process.wait(@pid)
    rescue Errno::ECHILD
    end

    @timeout.downto(0) do
      sleep 1
      exit unless running?
    end

    Process.kill 9, @pid if running?
    execute_callback(:after_stop)

  else
    FileUtils.rm(@pid_file) if File.exists?(@pid_file)
    log(:info, "PID file not found. Is the daemon started?")
  end

rescue Errno::ENOENT
end