module Workety

Initialize, start, stop and join worker class Drop process privileges after initialize

initialize() then start() There is no strict order for stop and join - stop may be called before join

Use Workety.stop to shutdown process from within worker Use Workety.abort to shutdown and return exit code 1, thus leading to restart by watchdog

This is an implementation for threaded worker.

TODO: If worker does not have any threads then a different path should be given:

* no mutex/started/must_stop
* no Signal.threaded_trap
* no thread list on USR1
* Just instantiate the class and call .start on it, leaving signal handling to that class

Constants

STOP_SELF_WATCHDOG_TIMEOUT

Public Class Methods

abort() click to toggle source

Thread initialize/start occurs inside @mutex, so calling Workety.abort/stop/must_stop?/aborted? from within it will lead to “ThreadError: deadlock; recursive locking”

# File lib/workety/workety.rb, line 89
def abort
  stop_sequence(true)
end
aborted?() click to toggle source
# File lib/workety/workety.rb, line 97
def aborted?
  @mutex.synchronize { @aborted }
end
join() click to toggle source
# File lib/workety/workety.rb, line 67
def join
  rescue_exit { @thread.join }
end
loop() { || ... } click to toggle source
# File lib/workety/workety.rb, line 105
def loop
  until must_stop?
    yield
  end
end
must_stop?() click to toggle source
# File lib/workety/workety.rb, line 101
def must_stop?
  @mutex.synchronize { @must_stop } 
end
rescue_abort() { || ... } click to toggle source
# File lib/workety/workety.rb, line 112
def rescue_abort
  yield
rescue ScriptError, StandardError => exception
  begin
    exception.report!
  ensure
    Workety.abort
  end
end
start(class_name, user = nil, group = nil) click to toggle source
# File lib/workety/workety.rb, line 47
def start(class_name, user = nil, group = nil)
  rescue_exit do
    
    # Class initialize is the place to things you should do before dropping privilegies (like start listening at port 80).
    #
    @mutex.synchronize do
      Process.exit(!@aborted) if @must_stop
      @thread = class_name.constantize.new
    end

    Process.change_privilegies(user, group) if user || group
   
    @mutex.synchronize do
      Process.exit(!@aborted) if @must_stop
      @thread.start
      @started = true
    end
  end
end
stop() click to toggle source
# File lib/workety/workety.rb, line 93
def stop
  stop_sequence(false)
end
stop_sequence(aborted) click to toggle source
# File lib/workety/workety.rb, line 71
def stop_sequence(aborted)
  rescue_exit do
    @mutex.synchronize do
      @aborted = true if aborted
      
      unless @must_stop
        @must_stop = true
        
        Thread.rescue_exit { stop_watchdog }
        Thread.rescue_exit { @thread.stop } if @started
      end
    end
  end
end
stop_watchdog() click to toggle source

Timeout for stop() and join() When the process is stopped by a signal, watchdog or signal sender take care of timeout But when the process call Workety.stop/abort by itself, this timeout function will ensure successful termination

# File lib/workety/workety.rb, line 126
def stop_watchdog
  sleep Workety::STOP_SELF_WATCHDOG_TIMEOUT
  Thread.log "Timeout stopping process"
ensure
  Process.exit(false)
end