Custom Signals

donut.system uses the terms “signal” and “signal handling” because component behavior is extensible. Other component libraries use the term lifecycle, which doesn’t convey the sense of extensibility that’s possible with donut.system.

Out of the box, donut.system recognizes ::ds/start, ::ds/stop, ::ds/suspend, ::ds/resume, and ::ds/status signals, but it’s possible to handle arbitrary signals – say, or To do that, you just need to add a little configuration to your system:

(def system
  {::ds/defs    {;; components go here
   ::ds/signals {   {:order :topsort}
        {:order :reverse-topsort}}})

::ds/signals is a map where keys are signal names and values are configuration maps. The configuration keys are:

:order values can be :topsort or :reverse-topsort. This specifies the order that components’ signal handlers should be called. :topsort means that if Component A refers to Component B, then Component A’s handler will be called first; reverse is, well, the reverse.

:returns-instance? this determines whether the return value of the signal handler should be used to update the system’s instances, under ::ds/instances. You would set this to false if want to use the return value of the signal for some purpose other than updating the instance. The ::ds/status signal is set up this way because its purpose is to return status information.

The map you specify under ::ds/signals will get merged with your system’s default signal map, which is:

(def default-signals
  "which graph sort order to follow to apply signal, and where to put result"
  {::start   {:order             :reverse-topsort
              :returns-instance? true}
   ::stop    {:order             :topsort
              :returns-instance? true}
   ::suspend {:order             :topsort
              :returns-instance? true}
   ::resume  {:order             :reverse-topsort
              :returns-instance? true}
   ::status  {:order :reverse-topsort}})