Skip to content

donut.system.repl/restart not reload external config #28

@velios

Description

@velios

I encountered a problem when using an external config, which is only relevant for repl-driven development. For example, let's take part of the system.

(def dev-system
  {::ds/defs
   {:service
    {:api-server
     #::ds{:start
           (fn [{deps ::ds/config
                 system ::ds/system}]
             (let [global-config (get-in system [::ds/defs :components :global-config])
                   {:keys [service-map]} global-config
                   {:keys [main-db]} deps]
               (-> service-map
                   (create-api-server)
                   (http/start))))

           :stop (fn [{api-server ::ds/instance}]
                   (when api-server
                     (http/stop api-server)))
           :config {:main-db (ds/ref [:components :postgres-db])}}}

    :components
    {:global-config (load-file "config/development.clj")}
    
    ...}})

;; prepare repl instance
(defmethod ds/named-system ::ds/repl
  [_]
  (ds/system dev-system))

Then call (donut.system.repl/restart)

  1. The first launch will go fine and we will receive an instance of our system.
  2. Now let’s change something in the config that we pull from an external file, for example the port number for the server
  3. Restart and port number is still old. unexpected behaviour

This happens because the state of our system, described in dev-system def, was baked in at the moment when the namespace was loaded. Changes have occurred, but in a third-party file config/development.clj and there were no changes in the namespace containing the system and it did not need to re-evaluate ns.

I also doublecheck example from organization and configuration section of donut.system readme. Config also not reload in proposed solution. It's possible that I'm doing something wrong.

(defmethod ds/named-system :dev
  [_]
  (ds/system :base {[:env] (env-config :dev)}))

(defmethod ds/named-system :donut.system/repl
  [_]
  (ds/system :dev))

We have several options to get around this

  1. We can make dev-system defn instead of def
(defn dev-system
  []
  {::ds/defs
   {:service
    {:api-server
     ...}}})

;; now call as fn when prepare repl instance
(defmethod ds/named-system ::ds/repl
  [_]
  (ds/system (dev-system)))
  1. We can wrap our user ns like this
(defn restart
  []
  (require 'my-project.system :reload)

  (donut.system.repl/restart))

I don’t think the problem is relevant for running in production or test mode. But for repl development, this behavior was unexpected for me and I did not immediately understand why this was happening.

Ideally if donut.system.repl/restart respect this case. Or it can clearly indicate in the documentation that by loading a config from an external source via Aero or a similar method to system defined with def, there is a chance to shoot in the legs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions