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.1'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ SvDir

Create a new SvDir corresponding to the service directory path.



65
66
67
# File 'lib/sys/sv/svdir.rb', line 65

def initialize(path)
  @path        = path
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



37
38
39
# File 'lib/sys/sv/svdir.rb', line 37

def path
  @path
end

Instance Method Details

#down?Boolean

true if the service is not running.

Returns:

  • (Boolean)


171
172
173
# File 'lib/sys/sv/svdir.rb', line 171

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.



153
154
155
# File 'lib/sys/sv/svdir.rb', line 153

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


114
115
116
117
# File 'lib/sys/sv/svdir.rb', line 114

def log
  fn = File.join(@path, 'log')
  return self.class.new(fn) if File.directory? 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)


147
148
149
# File 'lib/sys/sv/svdir.rb', line 147

def normally_down?
  File.exist? 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)


136
137
138
# File 'lib/sys/sv/svdir.rb', line 136

def normally_up?
  ! normally_down?
end

#paused?Boolean

Returns true if the service is paused, that is, has received a SIGSTOP.

Returns:

  • (Boolean)


182
183
184
# File 'lib/sys/sv/svdir.rb', line 182

def paused?
  statusbytes.pauseflag != 0
end

#pidObject

Return the pid of the service running under this SvDir, or nil if no service is running.



165
166
167
168
# File 'lib/sys/sv/svdir.rb', line 165

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



84
85
86
87
88
89
90
91
# File 'lib/sys/sv/svdir.rb', line 84

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)


123
124
125
126
127
# File 'lib/sys/sv/svdir.rb', line 123

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)


176
177
178
# File 'lib/sys/sv/svdir.rb', line 176

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.



159
160
161
# File 'lib/sys/sv/svdir.rb', line 159

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)


188
189
190
# File 'lib/sys/sv/svdir.rb', line 188

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)


194
195
196
# File 'lib/sys/sv/svdir.rb', line 194

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