class Servolux::Server


server.startup
server.extend DebugSignal
}
logger.debug “hey look - a debug message”
logger.info “Running @ #{Time.now}”
server = Servolux::Server.new(‘Debugger’, :interval => 2) {
end
end
end
logger.level = :debug
@old_log_level = logger.level
else
@old_log_level = nil
logger.level = @old_log_level
if @old_log_level
@old_log_level ||= nil
def usr1
module DebugSignal
this is a module, it can be used with any Servolux::Server instance.
original log level each time SIGUSR1 is sent to the server process. Since
is sent to the process. The log level toggles between “debug” and the
This example shows how to change the log level of the server when SIGUSR1
=== Signals
== Examples
server.startup
end
end
puts “I’m alive and well @ #{Time.now}”
def run
class << server
server = Servolux::Server.new(‘Singleton’, :interval => 1)
Singleton Class
server.startup
server.extend MyServer
server = Servolux::Server.new(‘Module’, :interval => 1)
end
end
puts “I’m alive and well @ #{Time.now}”
def run
module MyServer
Extension
server.startup
server = MyServer.new(‘MyServer’, :interval => 1)
end
end
puts “I’m alive and well @ #{Time.now}”
def run
class MyServer < Servolux::Server
Inheritance
these methods. In a nutshell:
that Ruby provides for defining methods on objects can be used to define
the run method, signal handlers, and before/after methods. Any pattern
For more complex services you will need to define your own server methods:
server.startup
}
puts “I’m alive and well @ #{Time.now}”
server = Servolux::Server.new(‘Basic’, :interval => 1) {
initializer. This block will be used as the run method.
For simple, quick and dirty servers just pass a block to the Server
== Usage
truly dead.
guarnteed to NOT be called till after the run loop thread is well and
just after the run loop thread has died; the after_stopping method is
before the run loop thread is signaled for shutdown. The second is called
shutdown: before_stopping and after_stopping. The first is called just
Likewise, two other methods are called before and after the run loop is
actually been scheduled).
thread has been created (no guarantee is made that the run loop thread has
is created and started. The second is called just after the run loop
and after_starting. The first is called just before the run loop thread
methods are called before and after the run loop starts: before_starting
There are a few other methods that are useful and should be mentioned. Two
server.
In order to handle SIGUSR1 you would define a usr1 method for your
usr2 SIGUSR2 none
usr1 SIGUSR1 none
term SIGTERM shutdown
int SIGINT shutdown
hup SIGHUP none
——–----------—————-
Method | Signal | Default Action
recognized by the Server class:
(another alias for shutdown). The following signal methods are
alias for shutdown). Likewise, SIGTERM is handled by the term method
server instance. For example, SIGINT is hanlded by the int method (an
too). A few other signals can be handled by defining a few methods on your
shutdown the server by calling the shutdown method (provided by default,
SIGINT and SIGTERM are handled by default. These signals will gracefully
called within the run loop instead of a run method.
Optionally, you can provide a block to the new method and it will be
provide is a run method that will be called by the server’s run loop.
management, signal handling, run loop, logging, etc. All that you need to
The Server class provides for standard server features: process ID file
== Details
period of time either in the foreground or as a daemon.
Ruby. A server in this context is any process that should run for a long
The Server class makes it simple to create a server-type application in
== Synopsis

def create_pid_file

def create_pid_file
  logger.debug "Server #{name.inspect} creating pid file #{pid_file.inspect}"
  File.open(pid_file, 'w') {|fd| fd.write(Process.pid.to_s)}
end

def delete_pid_file

def delete_pid_file
  if test(?f, pid_file)
    logger.debug "Server #{name.inspect} removing pid file #{pid_file.inspect}"
    File.delete(pid_file)
  end
end

def initialize( name, opts = {}, &block )


* interval :: Sleep interval between invocations of the _block_
* pid_file :: Location of the PID file
* logger :: The logger instance this server will use
==== Options

loop at the configured interval.
_options_ hash. The _block_ is run inside a separate thread that will
Creates a new server identified by _name_ and configured from the

Server.new( name, options = {} ) { block }
call-seq:
def initialize( name, opts = {}, &block )
  @name = name
  @activity_thread = nil
  @activity_thread_running = false
  @mutex = Mutex.new
  @shutdown = nil
  self.logger   = opts.getopt :logger
  self.pid_file = opts.getopt :pid_file
  self.interval = opts.getopt :interval, 0
  if block
    eg = class << self; self; end
    eg.__send__(:define_method, :run, &block)
  end
  ary = %w[name logger pid_file].map { |var|
    self.send(var).nil? ? var : nil
  }.compact
  raise Error, "These variables are required: #{ary.join(', ')}." unless ary.empty?
end

def pid_file


the server name is used to create a PID file name.
Returns the PID file name used by the server. If none was given, then
def pid_file
  @pid_file ||= name.downcase.tr(' ','_') + '.pid'
end

def shutdown


be notified when the this +shutdown+ method is finished executing.
the server is completely stopped, use the +wait_for_shutdown+ method to
the +before_stopping+ or +after_stopping+ methods return. To make sure
It is entirely possible that the activity thread will stop before either

3) The 'after_stopping' method has returned.
2) The server's activity thread has stopped.
1) The 'before_stopping' method has returned.

things have occurred:
Stop the server if it is running. This method will return after three
def shutdown
  return self unless running?
  stop
  @mutex.synchronize {
    @shutdown.signal
    @shutdown = nil
  }
  self
end

def startup( wait = false )


shutdown by a signal.
flag is used to ensure that the server has shutdown completely when
+wait_for_shutdown+ method has been called from another thread. This
If +true+ is passed to this method, then it will not return until the

file is deleted when this method returns.
shutdown the server, starting and joining the server thread. The PID
Startup involves creating a PID file, registering signal handlers to

will not return until the server is shutdown.
Start the server running using it's own internal thread. This method
def startup( wait = false )
  return self if running?
  @mutex.synchronize {
    @shutdown = ConditionVariable.new
  }
  begin
    create_pid_file
    trap_signals
    start
    join
    wait_for_shutdown if wait
  ensure
    delete_pid_file
  end
  return self
end

def trap_signals

def trap_signals
  SIGNALS.each do |sig|
    m = sig.downcase.to_sym
    Signal.trap(sig) { self.send(m) rescue nil } if self.respond_to? m
  end
end

def wait_for_shutdown


blocked until the server has been safely stopped.
method has been called and has completed. The current thread will be
If the server has been started, this method waits till the +shutdown+
def wait_for_shutdown
  @mutex.synchronize {
    @shutdown.wait(@mutex) unless @shutdown.nil?
  }
  self
end