This isn't really a question, just curious if anyone has any thoughts/feedback on this pattern. I find it interesting that integrant offers these generic multimethods that you're free to sort of bestow your own meanings on within the context of your program, but I'm still wrapping my head around how that should work for me beyond init/halt. I have a program that I operate via the repl that I'm looking at adding integrant to manage its components. I'm starting to get the idea that I'll use it like this: • I'll use integrant-repl though I don't think that's too relevant to this discussion • init/halt should be called rarely, basically only on initial startup and cases where specifically I care about toally shutting things down. • suspend/resume will be used more commonly, e.g. I often want to change config during the course of operations. suspend/resume will be used to give the system new conifg. • The above is motivated by the fact that I have a relatively small number of components (just one really) that actually benefit from a suspend implementation, since they take a long time to totally halt/init. • In the case where the suspendable component has dependencies, I need to implement suspend resume for all transitive dependencies of it, where suspend does nothing and resume just returns the old thing if it's conf+dep instances didn't change, or halts/inits it if it did change. eg:
;;; "suspendable" component
(defmethod ig/suspend-key! :my/component [k instance]
(suspend instance))
(defmethod ig/resume-key :my/component [k {:keys [:my/dep] :as conf} old-conf old-instance]
(if (= conf old-conf)
(do
(println "resuming old instance")
(resume old-instance))
(do
(println "not resuming old instance")
(ig/halt-key! k old-instance)
(ig/init-key k conf))))
;;; Do this for all things :my/component depends on
(defmethod ig/suspend-key! :my/dep [k instance]
nil)
(defmethod ig/resume-key :my/dep [k conf old-conf old-instance]
(if (= conf old-conf)
old-instance
(do
(ig/halt-key! k old-instance)
(ig/init-key k conf))))
Any thoughts? Anyone else do this same thing?Immediately after posting this, I realize it might be good to just make something like a ::noop-suspend key and derive from that everything that I don't want to do anything with on suspend
Do you absolutely need to implement suspend/resume on those dependencies? If you don’t, integrant just falls back to halt!/init, right? And if those aren’t expensive, can you just leave it at that?
Then you would have to dissoc the deps in the resume-key implementation in the equality comparison, the way it does in the https://github.com/weavejester/integrant?tab=readme-ov-file#suspending-and-resuming right:
(defmethod ig/resume-key :adapter/jetty [key opts old-opts old-impl]
(if (= (dissoc opts :handler) (dissoc old-opts :handler))
(do (deliver @(:handler old-impl) (:handler opts))
old-impl)
(do (ig/halt-key! key old-impl)
(ig/init-key key opts))))
In my particular case I'm unable to resume my component with a new instance of one of its dependencies, it must be instantiated with them when it's init but can't have them replaced laterI'm unclear on how adding in more suspend/resumes relates to the equality check? The dissoc in the resume-key method example is to ensure that the adapter doesn't need to restart if only the handler is changed.