Skip to content

[Daemon] Reload daemons in development #373

Description

@rsamoilov

Description

Currently, when developing a Rage::Daemon subclass, any changes to the daemon's source file require a full server restart to take effect. This slows down the development feedback loop, especially for daemons that maintain persistent connections or run continuous loops — the kind of code where quick iteration is most valuable.

Rage should automatically detect changes to a daemon's source file and restart the daemon with the updated code, similar to how Rage already reloads controllers and other application code in development.

For example, if a developer is working on:

# app/daemons/event_consumer.rb
class EventConsumer < Rage::Daemon
  def perform
    loop do
      event = EventQueue.pop
      process(event)
    end
  end

  private

  def process(event)
    # developer is iterating on this logic
  end
end

Saving changes to app/daemons/event_consumer.rb should trigger the daemon to stop (calling cleanup if defined), reload the class, and start a new instance with the updated code — all without restarting the server.

Implementation

The mechanism should:

  1. Watch the daemon's source file. Determine which file defines the daemon class and monitor it for changes.
  2. Stop the running daemon. Stop the current instance by signalling it to exit.
  3. Reload the class. Remove the old constant and load the updated file.
  4. Start the new instance. Launch the daemon using the updated class definition.

Design considerations

  • Change detection mechanism. The daemon reloader should hook into the existing Rage::CodeLoader mechanism rather than introducing a separate watcher.
  • Graceful stop during reload. The daemon's perform method may be blocked (e.g. in a Redis subscribe or a sleep). The reload mechanism needs a way to interrupt it.
  • Development-only. This feature should only be active in the development environment. In production, daemons should never be auto-reloaded based on file changes.
  • Error handling. If the updated file has a syntax error or the reloaded class raises during initialization, the daemon should not silently disappear. Log the error clearly and either retry on the next file change or fall back to the previous version.

Tips

  • Review the Daemon API docs to understand daemon lifecycle, the cleanup method, and how restarts work after crashes.
  • Look at how Rage handles code reloading for controllers and other application classes in development to find existing infrastructure to build on.
  • Check the architecture doc to see how Rage's core components interact and to understand the design principles.
  • Read the contributing guide for coding conventions and design principles used across the codebase.
  • Before starting the implementation, please share your proposed design approach. Discussing the approach early will drastically increase the chances of acceptance and help avoid rework.
  • Feel free to ask any questions or request help in the comments below!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions