Chapter 11. Immutant Daemons
11.1. Introduction
Daemons are long-running services sharing the lifecycle of your application. Their chief benefit is as a highly available "singleton" service in a cluster of Immutants.
11.2. Starting a Daemon
The primary abstraction is the immutant.daemons/Daemon protocol, which prescribes two methods: start and stop. Daemon instances are passed to the immutant.daemons/create function along with a name. A JMX MBean is then created and the daemon started asynchronously. The stop function is automatically invoked when your application is undeployed.
A convenience function, immutant.daemons/daemonize, may be used to
encapsulate the creation of a Daemon
from two functions. It takes
three parameters:
name
- a name for referencing as a JMX MBeanstart
- a start function to be invoked asynchronouslystop
- a stop function that will be automatically invoked when your app is undeployed, providing a hook to cleanly teardown resources used by the daemon
In addition, the following options are supported:
Option | Default | Description |
---|---|---|
:singleton | true | Singleton daemons will only execute on one node in a cluster. If false, the daemon will run on every node. |
The :singleton
option only applies when deployed to a
cluster. Immutant provides automatic failover for singleton daemons:
should it crash, the daemon will be automatically started on another
node chosen at random, resulting in a robust, highly-available
service.
11.3. Examples
The following contrived examples show a simple mechanism for controlling a daemon via a shared atom.
First, using the Daemon protocol directly:
(ns example.init (:require [immutant.daemons :as daemon])) ;; Controls the state of our daemon (def done (atom false)) ;; An implementation of Daemon (defrecord Service [] daemon/Daemon (start [_] (reset! done false) (loop [i 0] (Thread/sleep 1000) (when-not @done (println i) (recur (inc i))))) (stop [_] (reset! done true))) ;; Register the daemon (daemon/create "mydaemon" (Service.) :singleton true)
And alternatively, passing two functions:
(ns example.init (:require [immutant.daemons :as daemon]) ;; Controls the state of our daemon (def done (atom false)) ;; Our daemon's start function (defn start [] (reset! done false) (loop [i 0] (Thread/sleep 1000) (when-not @done (do-something) (recur (inc i))))) ;; Our daemon's stop function (defn stop [] (reset! done true)) ;; Register the daemon (daemon/daemonize "mydaemon" start stop :singleton false)