I've also been investigating the nested system approach/problem.
The primary use case that I have is composing subsystems which are mostly
independent modules using a higher order system to run in one process. The
modules themselves can be easily extracted into separate applications thus
becoming their own top level systems which makes it desirable to keep their
system maps intact.
Components inside modules might depend on the *whole* modules, not their
constituent parts. This allows to have modules call each other through the
API's in-process as well as being easily replaced by remote endpoints when
separated into multiple processes.
This mostly works except for the components depending on other
modules/systems, e.g.:
(require '[com.stuartsierra.component :as cmp])
(defrecord X [x started]
cmp/Lifecycle
(start [this] (if started (println "Already started " x) (println
"Starting " x " " this)) (assoc this :started true))
(stop [this] (println "Stopping " x " " this) this))
(def sys1 (cmp/system-map :x (cmp/using (X. "depends on dep" nil) [:dep])))
(def sys2 (cmp/system-map :y (cmp/using (X. "depends on sys1" nil)
[:sys1])))
(def hsys (cmp/system-map :sys1 (cmp/using sys1 [:dep]), :sys2 (cmp/using
sys2 [:sys1]) :dep (X. "dependency" nil)))
(cmp/start hsys)
Starting dependency #user.X{:x dependency, :started nil}
Already started dependency
Starting depends on dep #user.X{:x depends on dep, :started nil, :dep
#user.X{:x dependency, :started true}}
clojure.lang.ExceptionInfo: Error in component :sys2 in system
com.stuartsierra.component.SystemMap calling
#'com.stuartsierra.component/start
clojure.lang.ExceptionInfo: Missing dependency :dep of clojure.lang.Keyword
expected in system at :dep
This happens because of the following:
1. Dependency :*dep* of *sys1* is started in *hsys*
2. *sys1* is started (:*dep* is started again, so the start/stop should be
idempotent)
3. Dependency :*sys1* of *sys2* is started in *hsys*
4. :*sys1* cannot be started as it depends on :*dep* which isn't present in
*sys2*
This scenario could be supported by the Component library in several ways:
1. introduce an IdempotentLifecycle protocol which will be respected by the
Component library. Implement the protocol for the SystemMap.
IdempotentLifecycles will not be started or stopped for the second time,
also their dependencies will not be updated if they are already started.
2. do not fail if a component already has a dependency under the specified
key. This is a hack compared to the first solution, but I might go with it
in the short term.
Stuart, what do you think about that? Would you consider a PR implementing
the first proposal?
On Wednesday, March 18, 2015 at 10:18:36 AM UTC+1, Stuart Sierra wrote:
>
>
> On Tue, Mar 17, 2015 at 5:47 PM, James Gatannah <[email protected]
> <javascript:>> wrote:
>
>> FWIW, we've been using something that smells an awful lot like nested
>> systems for months now. I never realized we weren't supposed to.
>>
>
>
> It's not that nested systems *never* work, but from what I've seen they
> cause more complications than they're worth. The 'component' model doesn't
> forbid it, but it does not support dependencies between components in
> different "subsystems."
>
> I've found it easier to keep system maps "flat" and use namespaced
> keywords to distinguish "subsystem" groups, even in large systems with 30+
> components.
>
> –S
>
>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.