Ruby Daemons Documentation

repository·master·Indexed 20 days ago

https://github.com/thuehlinger/daemons

A utility for wrapping Ruby scripts or blocks of code to run as background daemon processes. It provides a standardized CLI and programmatic interface to start, stop, restart, and monitor processes. Key features include the Daemons.run and Daemons.run_proc methods for wrapper scripts, Daemons.call for spawning tasks from within applications, and Daemons.daemonize for backgrounding the current process. It includes an ApplicationGroup class for managing collections of related daemonized applications.

Tokens
11K
Snippets
35
Records
47
Agent score
71%

What's inside Ruby Daemons

  1. Run a Ruby block as a daemon process

    master

    If you want to run a specific block of Ruby code in the background rather than an external file, use Daemons.run_proc('name.rb'). This allows you to include the logic directly within your control script while still providing the same start/stop/restart/run/status CLI interface as the file-based wrapper.

    # myproc_control.rb
    require 'daemons'
    
    Daemons.run_proc('myproc.rb') do
      loop do
        sleep(5)
      end
    end
  2. Wrap an existing Ruby script as a daemon

    master

    To run an existing Ruby script (e.g., a server) in the background with start/stop/restart capabilities, use Daemons.run('script_name.rb') in a wrapper script.

    This method detaches the script from the console, forks it into the background, and releases directories and file descriptors. You can pass additional arguments to the target script by separating them from the control script arguments with a double hyphen --.

    Common CLI commands for the wrapper script:

    • start: Runs the script in the background.
    • stop: Stops the daemon.
    • restart: Restarts the daemon.
    • run: Runs the script in the foreground (useful for testing without forking).
    • status: Displays whether the daemon is running and its PID.
    # myserver_control.rb
    require 'daemons'
    
    Daemons.run('myserver.rb')
    # Start the daemon
    $ ruby myserver_control.rb start
    
    # Pass arguments to the daemonized script
    $ ruby myserver_control.rb start -- --file=anyfile --a_switch another_argument
    
    # Run in foreground for testing
    $ ruby myserver_control.rb run
  3. Understand Pid-File naming and storage

    master

    A Pid-File stores the process identification number (PID) of a running daemon, allowing other programs to send signals (like TERM to stop the process).

    Naming Convention

    • If only one instance is allowed: <scriptname>.pid
    • If multiple instances are allowed: <scriptname>_num<number>.pid (where <number> is an integer).
    • The default delimiter used is _num.

    Storage Modes

    When configuring Daemons, you can choose where these files reside using the :dir_mode option:

    1. :script: A directory relative to the script being daemonized.
    2. :normal: A directory specified by the :dir option.
    3. :system: The preconfigured /var/run directory.
  4. How Daemons handles process daemonization

    master

    When a process is daemonized by the Daemons library, the following technical steps occur:

    1. Forking: Forks a child process and exits the parent.
    2. Session Leadership: Becomes a session leader to detach from the controlling terminal.
    3. Double Fork: Forks a second child and exits the first child to prevent re-acquiring a controlling terminal.
    4. Working Directory: Changes the current working directory to /.
    5. Umask: Clears the file creation mask (sets umask to 0000).
    6. File Descriptors: Closes file descriptors and reopens $stdout and $stderr to point to a logfile if possible.

    Consequences for your code:

    • The current directory is always /.
    • You cannot receive input from the console (e.g., gets will not work).
    • You cannot output to the console via puts or print unless you have configured log redirection.
  5. Configure application start modes in Daemons::Application

    master

    The Daemons::Application#start method behaves differently depending on the :mode option provided in the configuration:

    • :none: Used to daemonize the currently running process (via Daemons.daemonize).
    • :exec: Uses Kernel.exec to replace the current process with the configured script. Environment variable DAEMONS_ARGV is set to the controller arguments.
    • :load: Loads the configured script into the current Ruby process. Environment variables DAEMONS_ARGV and ARGV are adjusted to match the application's arguments.
    • :proc: Runs a specific Ruby proc (provided via the :proc option) as a daemon. This is useful for running in-memory logic without a separate script file.

    Note: If the :ontop option is set, the application runs in the foreground (simulated mode) instead of daemonizing.

  6. Configure SyslogIO buffering and synchronization

    master

    Daemons::SyslogIO supports two buffering modes controlled by the sync attribute:

    • Line Buffered (Default): When sync is false, output is buffered and flushed whenever a newline (\n) is encountered. This is generally optimal for syslog to ensure complete log lines.
    • Synchronous IO: When sync is true, output is written immediately via syswrite, bypassing the internal buffer.

    You can manually trigger a flush of any buffered data using the flush method.

    syslog_io = Daemons::SyslogIO.new("myapp")
    
    # Enable synchronous mode
    syslog_io.sync = true
    
    # Or use line buffering (default)
    syslog_io.sync = false
    
    # Manually flush buffer
    syslog_io.flush
  7. Use SyslogIO to redirect IO to syslog

    master

    Daemons::SyslogIO is a class that allows you to use syslog through an IO-like interface. You can wrap standard streams like $stdout and $stderr so that all output from your application is automatically sent to the system logger.

    When initializing, you can provide an identifier, syslog facility, log level, syslog options, and an optional IO object for passthrough (where text is written to both syslog and the provided IO).

    Note: Multiple SyslogIO objects share the same underlying syslog connection. The identifier is shared and will be set to the value of the last object created. Syslog options are merged across all objects, but facility and level are distinct per instance.

    require 'syslogio'
    
    # Redirect stdout to syslog with info level
    $stdout = Daemons::SyslogIO.new("myapp", :local0, :info, $stdout)
    
    # Redirect stderr to syslog with error level
    $stderr = Daemons::SyslogIO.new("myapp", :local0, :err, $stderr)
    
    $stdout.puts "This is a message"
    $stderr.puts "This is an error"
    
    # Errors will also be captured by the $stderr SyslogIO
    raise StandardError, 'This will get written through the SyslogIO for $stderr'
  8. Customize the daemon status display

    master

    By default, ruby control_script.rb status shows if the daemon is running and its PID. You can provide a custom status message by passing a :show_status_callback key in the options hash to Daemons.run. The callback receives an app object which provides access to the PID and other metadata.

    def custom_show_status(app)
      # Display the default status information
      app.default_show_status
    
      puts "PS information"
      system("ps -p #{app.pid.pid.to_s}")
    end
    
    Daemons.run('myserver.rb', { show_status_callback: :custom_show_status })
  9. Daemonize the currently running process

    master

    To turn the currently executing Ruby process into a daemon (without the ability to be controlled via start/stop CLI commands), call Daemons.daemonize. This is typically used after performing initial application setup/initialization while still in the foreground.

    require 'daemons'
    
    # Perform foreground initialization
    init()
    
    # Become a daemon
    Daemons.daemonize
    
    # Enter the main loop
    loop do
      # server logic
    end
  10. Control multiple daemons from a parent application

    master

    You can spawn and manage multiple daemon tasks directly from within a running Ruby application using Daemons.call.

    • Use Daemons.call for a single daemon task. It returns a task object that can be used to control the process (e.g., task.stop).
    • Use Daemons.call(:multiple => true) to spawn multiple daemon tasks.
    require 'daemons'
    
    task1 = Daemons.call(:multiple => true) do
      loop do
        # task logic
        sleep(5)
      end
    end
    
    task2 = Daemons.call do
      loop do
        # task logic
        sleep(5)
      end
    end
    
    # Control the tasks
    task1.stop
    task2.stop
  11. Configure signal handling and shutdown behavior

    master

    You can control how Daemons::Application handles process termination and signal sequences.

    Signal Sequences

    The :signals_and_waits option accepts a string formatted as SIGNAL:WAIT|SIGNAL:WAIT. This defines the sequence of signals sent during a stop operation and how long to wait after each.

    Example format: TERM:10|KILL:5 (Send TERM, wait 10s, then send KILL, wait 5s).

    Exit Behavior

    • :hard_exit: If set to true, the application will use exit! to terminate, preventing at_exit handlers from running. Use this carefully as it may prevent PID file cleanup.
    • :backtrace: If set to true, the application will attempt to write an exception log if it exits due to an error (provided it is not in :ontop mode and didn't exit via SIGTERM).
  12. Configure Daemons::Reporter output suppression

    master

    The Daemons::Reporter accepts an options hash in its constructor. To silence all status and system messages, use the :shush option.

    • options[:shush] = true: Disables all output via output_message and prevents $stdout.sync = true from being set.
    # To suppress all output:
    reporter = Daemons::Reporter.new(shush: true)