Class: Sys::Sv::SvDir
- Inherits:
-
Object
- Object
- Sys::Sv::SvDir
- Defined in:
- lib/sys/sv/svdir.rb
Overview
The SvDir class encapsulates service directories, a scheme for reliably controlling daemon processes (services) introduced in Dan Bernstein’s daemontools
software.
Each service is monitored by a supervisor, which is responsible for starting, stopping, restarting and generally controlling the service. Examples of such supervisors include supervise
from the daemontools
package and runsv
from Gerit Pape’s compatible runit
software.
Most SvDir methods will raise Errno::
exceptions (each a subclass of SystemCallException
) if the underlying filesystem representation of the service directory is not as expected. For example, EACCESS
or ENOENT
may be raised if the supervisor’s status directory or state files are missing or unreadable. Additionally, ENXIO
is raised if the supervisor itself isn’t running.
Constant Summary collapse
- VERSION =
'0.2'
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
-
#down? ⇒ Boolean
true
if the service is not running. -
#downtime ⇒ Object
Returns the number of seconds the service has been down, as a float, or
nil
if the service is in fact running. -
#initialize(path) ⇒ SvDir
constructor
Create a new SvDir corresponding to the service directory
path
. -
#log ⇒ Object
Return a SvDir object representing this service’s attendant
log
service, otherwisenil
. -
#normally_down? ⇒ Boolean
Returns
true
if a supervisor will not start the service without explicit instruction to do so. -
#normally_up? ⇒ Boolean
Returns
true
if the service is typically running, i.e., if the service directory lacks a./down
file. -
#paused? ⇒ Boolean
Returns
true
if the service is paused, that is, has received a SIGSTOP. -
#pid ⇒ Object
Return the pid of the service running under this SvDir, or
nil
if no service is running. -
#signal(cmd) ⇒ Object
Send a signal to the service via its supervisor.
-
#svok? ⇒ Boolean
Returns
true
if the service directory’s supervisor is running. -
#up? ⇒ Boolean
true
if the service is running, even if paused. -
#uptime ⇒ Object
Returns the number of seconds the service has been running, as a float, or
nil
if the service is not running. -
#want_down? ⇒ Boolean
Returns
true
if the service’s supervisor has been instructed to bring the service down. -
#want_up? ⇒ Boolean
Returns
true
if the service’s supervisor has been instructed to bring the service up.
Constructor Details
#initialize(path) ⇒ SvDir
Create a new SvDir corresponding to the service directory path
.
62 63 64 |
# File 'lib/sys/sv/svdir.rb', line 62 def initialize(path) @path = path end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
36 37 38 |
# File 'lib/sys/sv/svdir.rb', line 36 def path @path end |
Instance Method Details
#down? ⇒ Boolean
true
if the service is not running.
168 169 170 |
# File 'lib/sys/sv/svdir.rb', line 168 def down? pid.nil? end |
#downtime ⇒ Object
Returns the number of seconds the service has been down, as a float, or nil
if the service is in fact running.
150 151 152 |
# File 'lib/sys/sv/svdir.rb', line 150 def downtime return elapsed() if down? end |
#log ⇒ Object
Return a SvDir object representing this service’s attendant log
service, otherwise nil
.
Typical SvDir daemons contain a “nested” SvDir responsible for logging the stdout of the base service. E.g.:
/path/to/services/webserver # <--- base service
/path/to/services/webserver/log # <--- logger
The log
service is supervised and controllable just like the base service. (Also, the pipe connecting the base service’s stdout to the log
service’s stdin is maintained by a common parent, so that restarting either service won’t lose data in the pipe.)
Example:
my_serv = Sys::Sv::SvDir.new("path/to/my_serv")
my_serv.signal(:down)
if logger = my_serv.log
logger.signal(:down)
end
111 112 113 114 |
# File 'lib/sys/sv/svdir.rb', line 111 def log fn = File.join(@path, 'log') return self.class.new(fn) if File.exists? fn end |
#normally_down? ⇒ Boolean
Returns true
if a supervisor will not start the service without explicit instruction to do so.
Note that this method functions whether or not the service is running, and whether or not a supervisor is running.
See also the #want_down? method documentation.
144 145 146 |
# File 'lib/sys/sv/svdir.rb', line 144 def normally_down? File.exists? File.join(@path, 'down') end |
#normally_up? ⇒ Boolean
Returns true
if the service is typically running, i.e., if the service directory lacks a ./down
file.
Note that this method functions whether or not the service is running, and whether or not a supervisor is running.
See also the #want_up? method documentation.
133 134 135 |
# File 'lib/sys/sv/svdir.rb', line 133 def normally_up? ! normally_down? end |
#paused? ⇒ Boolean
Returns true
if the service is paused, that is, has received a SIGSTOP.
179 180 181 |
# File 'lib/sys/sv/svdir.rb', line 179 def paused? statusbytes.pauseflag != 0 end |
#pid ⇒ Object
Return the pid of the service running under this SvDir, or nil
if no service is running.
162 163 164 165 |
# File 'lib/sys/sv/svdir.rb', line 162 def pid p = statusbytes.pid return p == 0 ? nil : p end |
#signal(cmd) ⇒ Object
Send a signal to the service via its supervisor.
:up
-
start the service if not running, restarting as necessary.
:down
-
stop the service, issuing a TERM followed by a CONT. Do not restart it if it stops.
:once
-
start the service if not running, but do not restart it if it stops.
:pause
or:STOP
-
issue a STOP signal. See also #paused?.
:continue
or:CONT
-
issue a CONT signal. See also #paused?.
:hangup
or:HUP
-
issue a HUP signal.
:alarm
or:ALRM
-
issue an ALRM signal.
:interrupt
orINT
-
issue an INT signal.
:terminate
orTERM
-
issue a TERM signal.
:kill
orKILL
-
issue a KILL signal.
:exit
-
tell the supervisor to exit as soon as the service stops.
:user1
or:USR1
-
issue a USR1 signal. Not supported by all supervisors
:user2
or:USR2
-
issue a USR2 signal. Not supported by all supervisors
81 82 83 84 85 86 87 88 |
# File 'lib/sys/sv/svdir.rb', line 81 def signal(cmd) unless byte = Commands[cmd.to_sym] raise ArgumentError.new("unsupported SvDir signal `#{cmd}'") end Util::open_write(svfn('control')) do |f| f.syswrite(byte) end end |
#svok? ⇒ Boolean
Returns true
if the service directory’s supervisor is running.
To determine whether the service itself is running, see #up?, #down? and #paused?
120 121 122 123 124 |
# File 'lib/sys/sv/svdir.rb', line 120 def svok? Util::open_write(svfn('ok')) { true } rescue Errno::ENXIO, Errno::ENOENT false # No pipe reader, or no pipe! end |
#up? ⇒ Boolean
true
if the service is running, even if paused.
173 174 175 |
# File 'lib/sys/sv/svdir.rb', line 173 def up? !down? end |
#uptime ⇒ Object
Returns the number of seconds the service has been running, as a float, or nil
if the service is not running.
156 157 158 |
# File 'lib/sys/sv/svdir.rb', line 156 def uptime return elapsed() if up? end |
#want_down? ⇒ Boolean
Returns true
if the service’s supervisor has been instructed to bring the service down.
185 186 187 |
# File 'lib/sys/sv/svdir.rb', line 185 def want_down? statusbytes.wantflag == 'd' end |
#want_up? ⇒ Boolean
Returns true
if the service’s supervisor has been instructed to bring the service up.
191 192 193 |
# File 'lib/sys/sv/svdir.rb', line 191 def want_up? statusbytes.wantflag == 'u' end |