Module: Workety

Defined in:
lib/workety/workety.rb

Overview

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

Defined Under Namespace

Classes: TestThread

Constant Summary collapse

STOP_SELF_WATCHDOG_TIMEOUT =
65

Class Method Summary collapse

Class Method Details

.abortObject

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



89
90
91
# File 'lib/workety/workety.rb', line 89

def abort
  stop_sequence(true)
end

.aborted?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/workety/workety.rb', line 97

def aborted?
  @mutex.synchronize { @aborted }
end

.joinObject



67
68
69
# File 'lib/workety/workety.rb', line 67

def join
  rescue_exit { @thread.join }
end

.loopObject



105
106
107
108
109
# File 'lib/workety/workety.rb', line 105

def loop
  until must_stop?
    yield
  end
end

.must_stop?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/workety/workety.rb', line 101

def must_stop?
  @mutex.synchronize { @must_stop } 
end

.rescue_abortObject



112
113
114
115
116
117
118
119
120
# 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) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 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

.stopObject



93
94
95
# File 'lib/workety/workety.rb', line 93

def stop
  stop_sequence(false)
end

.stop_sequence(aborted) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 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_watchdogObject

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



126
127
128
129
130
131
# 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