Class: Sys::Sv::SvDir

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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

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

Returns:

  • (Boolean)


168
169
170
# File 'lib/sys/sv/svdir.rb', line 168

def down?
  pid.nil?
end

#downtimeObject

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

#logObject

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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


179
180
181
# File 'lib/sys/sv/svdir.rb', line 179

def paused?
  statusbytes.pauseflag != 0
end

#pidObject

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 or INT

issue an INT signal.

:terminate or TERM

issue a TERM signal.

:kill or KILL

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?

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


173
174
175
# File 'lib/sys/sv/svdir.rb', line 173

def up?
  !down?
end

#uptimeObject

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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


191
192
193
# File 'lib/sys/sv/svdir.rb', line 191

def want_up?
  statusbytes.wantflag == 'u'
end