integrant

Ernesto Garcia 2025-09-25T13:33:13.026349Z

I'm currently using Integrant for starting some TestContainers for some automated tests. During a test, I would want to turn off one of the containers for some seconds, then turn it on again. What would be the way to achieve this? I have tried to suspend! the key, but resumeing will start extra containers for keys that were already running.

Ernesto Garcia 2025-10-01T11:39:08.568419Z

> Currently you'd need to do this manually by passing the same set of keys to both suspend! and resume. Only that resume will halt keys in the system that are not passed to it.

weavejester 2025-10-01T12:34:11.320449Z

Ah, right! I'd forgotten. I believe that's so it behaves the same way as init.

weavejester 2025-10-01T12:35:10.111149Z

Adjusting resume so that it knows about which keys were suspended sounds like a reasonable update, but I'll give it a little thought first.

👍 1
🙏 1
weavejester 2025-09-26T22:05:44.839319Z

In this case, I'd access the system map directly, assuming that suspending and resuming the container key can be done in isolation. Something like this, perhaps:

(defn suspend-container-key [system key]
  (ig/suspend-key! key (get system key)))

(defn resume-container-key [system key]
  (let [config (-> system meta ::ig/origin)
        value  (get config key)]
    (update system #(ig/resume-key key value value %))))

weavejester 2025-09-26T22:07:08.428959Z

Alternatively, if you have a .start and .stop on your container you could do it:

(defn stop-container-key [system key]
  (.stop (get system key)))

(defn start-container-key [system key]
  (.start (get system key)))

Ernesto Garcia 2025-09-30T08:52:54.713329Z

I see, Integrant doesn't keep track of whether a key has been halted/suspended. So it doesn't know what keys are actually reusable, right?

weavejester 2025-09-30T13:59:39.235889Z

Kinda right. Suspend/resume are methods designed to allow keys in development to reuse resources. When you implement these methods, you're telling Integrant that it can reuse resources under circumstances you control. For example, if you have a database connection pool, and you know that the configuration is unchanged, there's no need to shut it down - you can reuse it without issue. Similarly, if you have a web server, and you know that only the handler function has changed, you can update the handler without restarting the web server. Otherwise, you can fall back to the default halt/init. The purpose of this is to both speed up restarts in a development environment, and to prevent interruptions caused by closing connections. It's not designed as a way of partially stopping/starting a configuration. That said, there's no reason we couldn't record which keys are suspended in the metadata of the system, and then to only resume those specific keys when we resume. Currently you'd need to do this manually by passing the same set of keys to both suspend! and resume.

Ernesto Garcia 2025-09-29T09:03:51.770219Z

Yeah, actually .stopping and .starting works. Don't know why I was under the impression that a TestContainer wasn't restartable. Thanks for your response!

Ernesto Garcia 2025-09-29T09:07:24.898199Z

However, shouldn't resume not start again keys that are already been started? Its docs says:

integrant.core/resume
[config system]
[config system keys]

Turn a config map into a system map, reusing resources from an existing
system when it's possible to do so.

weavejester 2025-09-29T09:33:23.401529Z

Only if you explicitly write suspend-key! and resume-key to re-use resources. It wasn't designed with partial restarts in mind; rather, suspend/resume are for things like keeping the server and other connections open between restarts.

Ernesto Garcia 2025-09-29T09:45:10.368039Z

Yes, I noticed that when looking into the library code. Suspending falls back to halting when suspend-key! is not defined, which makes suspend-key! kind of optional. Couldn't resume behave the same way when suspend-key! is not defined for a key, i.e. reuse already init'ed resources? The current behavior seems to get us onto unexpected/inconsistent system state.

weavejester 2025-09-29T09:48:10.062769Z

You mean in the case that suspend! is applied only to a subset of keys?

Ernesto Garcia 2025-09-29T09:49:18.301889Z

In any case... does it make a difference?

weavejester 2025-09-29T09:59:32.832169Z

If a key has been halted, it needs to be re-initiated, so can't be re-used. Only keys with suspend-key! implementations can potentially be re-used. Or keys that weren't included in the suspend! call in the first place. I guess I could record the subset of keys passed to suspend! and only trigger these for resume, if resume doesn't get keys of its own.