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

#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.

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

Raises:

  • (RuntimeError)

    Raise exception if path does not exist

  • (RuntimeError)

    Raise exception if path is not readable or writable.


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/pidly/control.rb', line 63

def initialize(options={})

  @messages = []

  @error_count = 0

  @name = options.fetch(:name)

  @path = if options.has_key?(:path)
    Pathname.new(options.fetch(:path))
  else
    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

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

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

  @pid = fetch_pid

  @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, true)

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

  validate_callbacks!

  validate_files_and_paths!
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

Examples:

Test.spawn(
  :path => '/tmp',
  :verbose => true
)

Parameters:

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

    Control object options

Returns:

See Also:


131
132
133
# File 'lib/pidly/control.rb', line 131

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

Instance Method Details

#clean!Object

Clean

Remove all files created by the daemon.


293
294
295
296
297
# File 'lib/pidly/control.rb', line 293

def clean!
  FileUtils.rm(@log_file)
  FileUtils.rm(@pid_file)
rescue Errno::ENOENT
end

#fetch_class_var(name) ⇒ Symbol, ...

Fetch Class Variable

Parameters:

  • name (Symbol)

    Callback name

Returns:

  • (Symbol, Proc, nil)

    Returns either a method or block of code to be executed when the callback is called. If no value is accossiated with the call variable `nil` will be returned to the caller.


309
310
311
312
313
314
315
# File 'lib/pidly/control.rb', line 309

def fetch_class_var(name)
  Control.instance_eval do
    return nil unless class_variable_defined?(:"@@#{name}")

    class_variable_get(:"@@#{name}")
  end
end

#kill(remove_pid_file = true) ⇒ Object

Kill

Parameters:

  • remove_pid_file (String) (defaults to: true)

    Remove the daemon pid file


261
262
263
264
265
266
267
268
269
270
# File 'lib/pidly/control.rb', line 261

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

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

#restartObject

Restart

Restart the daemon


252
253
254
# File 'lib/pidly/control.rb', line 252

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

#running?true, false

Running?

Returns:

  • (true, false)

    Return the running status of the daemon.


277
278
279
280
281
282
283
284
285
286
# File 'lib/pidly/control.rb', line 277

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


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
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/pidly/control.rb', line 140

def start

  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


239
240
241
242
243
244
245
# File 'lib/pidly/control.rb', line 239

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


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/pidly/control.rb', line 202

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, "\"#{@name}\" PID file not found.")
  end

rescue Errno::ENOENT
end