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 <james.g...@gmail.com > <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 clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com 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 clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.