Class: Rage::Daemon

Inherits:
Object
  • Object
show all
Defined in:
lib/rage/daemon.rb

Overview

Rage::Daemon is an abstraction for running long-lived background processes alongside your application. Use daemons for tasks that need to run continuously, such as listening to message queues, consuming streaming APIs, or maintaining persistent connections to external services.

The framework automatically manages daemon lifecycle:

  • Daemons are started when the server boots
  • If a daemon exits or crashes, Rage restarts it with exponential backoff
  • If a worker process dies, Rage restarts the daemon in another worker
  • On server shutdown, daemons are gracefully stopped

Defining a Daemon

Create a daemon by subclassing Rage::Daemon and implementing the #perform method:

class RedisListener < Rage::Daemon
  def perform
    redis = Redis.new

    redis.subscribe("notifications") do |on|
      on.message do |channel, message|
        Rage::Cable.broadcast("notifications", message)
      end
    end
  end
end

Registering Daemons

Register daemons in your application configuration:

# config/application.rb
Rage.configure do
  config.daemons << RedisListener
end

Daemon Scope

By default, daemons run in exactly one worker process per server. Use scope to change this behavior:

class MetricsCollector < Rage::Daemon
  scope :worker

  def perform
    # runs in every worker process
  end
end

Stopping a Daemon

Return Stop from #perform to explicitly stop a daemon without triggering a restart:

class BatchProcessor < Rage::Daemon
  def perform
    while (batch = Batch.next_pending)
      process(batch)
    end

    Stop  # all batches processed, stop the daemon
  end
end

Cleanup

Implement the cleanup method to release resources when a daemon stops or restarts:

class StreamConsumer < Rage::Daemon
  def perform
    @connection = StreamingAPI.connect
    @connection.each { |event| process(event) }
  end

  def cleanup
    @connection&.close
  end
end

The cleanup method is called:

  • When #perform returns normally
  • When #perform raises an exception (before restart)
  • When the server is shutting down

Constant Summary collapse

Stop =

A sentinel value that can be returned from #perform to explicitly stop the daemon. When returned, the daemon will not be restarted.

Examples:

def perform
  return Stop if shutdown_requested?
  # ...
end
Object.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.scope(level) ⇒ Object

Configures the scope at which the daemon runs.

By default, daemons run in one worker process per server (:node scope). Use this method to change the scope when a different behavior is needed.

Examples:

Running in every worker

class MetricsCollector < Rage::Daemon
  scope :worker

  def perform
    # runs in every worker process
  end
end

Parameters:

  • level (Symbol)

    the scope level

Options Hash (level):

  • :node (Object)

    One instance per server (default). Rage uses IPC to coordinate which worker runs the daemon. If that worker dies, the daemon restarts in another worker.

  • :worker (Object)

    One instance per worker process. Use this when the daemon performs work that needs to run in parallel across workers.



137
138
139
140
141
142
143
# File 'lib/rage/daemon.rb', line 137

def scope(level)
  unless level == :worker || level == :node
    raise ArgumentError, "Invalid scope level: #{level.inspect}. Valid options are :node and :worker."
  end

  @__level = level
end

Instance Method Details

#performObject

The main entry point for the daemon's work.

Implement this method to define what the daemon does. The method should contain the daemon's main loop or blocking operation. When this method returns normally, Rage logs a warning and restarts the daemon. Return Stop to explicitly stop the daemon without triggering a restart.

Examples:

Listening to a Redis channel

def perform
  redis = Redis.new
  redis.subscribe("events") do |on|
    on.message { |_, msg| handle(msg) }
  end
end

Polling a queue

def perform
  loop do
    message = queue.pop
    process(message)
  end
end

Processing until complete

def perform
  while (item = fetch_next_item)
    process(item)
  end

  Stop
end

Returns:

  • (Object)

    return Stop to stop the daemon; any other return value triggers a restart



233
234
# File 'lib/rage/daemon.rb', line 233

def perform
end