tolitius / mount

managing Clojure and ClojureScript app state since (reset)
Eclipse Public License 1.0
1.22k stars 88 forks source link

How to refresh business logic and restart affected components automatically? #94

Open theronic opened 6 years ago

theronic commented 6 years ago

Hey Anatoly. Mount looks pretty cool - I like the idea of using the build system to handle dependencies instead of reimplementing the dependency graph.

Been using boot-clj, system.component and danielsz's system. Some of my lifecycle components like Ring handlers are constructed dynamically, which makes it hard to reload web handlers automatically.

I glossed over the mount README and downloaded and ran examples like Neo, but it's not obvious how I can automatically trigger a reload ((reset)?) when code is changed. If I edit this file and save, I don't see any reload notices (can I log this?), but I can call (reset) to see any changes.

Using Cursive as my IDE, and maybe I need to add some tooling there to run (reset) on save?

Especially for beginners, would greatly appreciate a GIF showing what kind of workflow is supported for auto-reloading, because I've spent so much time trying to figure out why my handlers don't respond the way the code looks, until I realised I need to manually reload components (which can take a long time for many components). Not saying this is something mount doesn't live up to, but something I would like to do :).

tolitius commented 6 years ago

Hi Petrus,

Here is the place in the docs that talks about restarting on recompile.

I use vi for development, but some of my coworkers do use Cursive and auto component restart works there as well.

As long as the editor (vi, IntelliJ, Emacs, etc.) recompiles the file on save, mount will restart all the affected states.

The flow is quite simple:

  1. open terminal A
  2. A: cd to neo root directory: i.e. [neo]$
  3. A: run boot repl
  4. A: once inside the REPL, run (dev)(reset)

this would start the app

  1. open terminal B
  2. open "src/neo/www.clj" with the editor
  3. recompile it

You'll see this in the terminal A:

dev=> INFO  utils.logging - >> starting.. #'neo.www/neo-app

and this is what I see in vi (you should see the same message in other editors):

let me know whether this helps.

boxxxie commented 3 years ago

I have a similar problem, i have a yada/bidi web server that requires vhost structures that are defined in other files, when i change/compile a vhost def, my webserver does not stop/start, which means everytime i change a vhost i have to go to the repl and do a manual (reset)

even if i wrap the vhost stuff in a defstate, only the vhost defstate does stop/start on compile, not the webserver.

example of the server, each .../routes is a defstate. everything works fine cept the server doesn't restart when it's deps are recompiled/restarted.

(defstate server
  :start (start-server config
                       prelaunch/routes
                       backoffice/routes
                       storybook/routes)
  :stop  (stop-server server))

here is my state tree. the gateway/server is missing :deps prelaunch/routes, backoffice/routes, storybook/routes so, i'm doing something that mount doesn't like, i'm not really sure what though, but if i figure this out then it probably would be good to add something to the readme related to this problem.

({:name "#'my-project.config/config", :order 1, :status #{:started}, :deps #{}}
 {:name "#'my-project.sendpulse/mail", :order 2, :status #{:started}, :deps #{"#'my-project.config/config"}}
 {:name "#'my-project.mail/send", :order 3, :status #{:started}, :deps #{"#'my-project.config/config"}}
 {:name "#'my-project.web.forms.malli/coercer", :order 4, :status #{:started}, :deps #{"#'my-project.config/config"}}
 {:name "#'my-project.db/conn", :order 5, :status #{:started}, :deps #{"#'my-project.config/config"}}
 {:name "#'my-project.web.storybook/routes", :order 6, :status #{:started}, :deps #{"#'my-project.config/config"}}
 {:name "#'my-project.web.backoffice/routes",
  :order 7,
  :status #{:started},
  :deps #{"#'my-project.web.forms.malli/coercer" "#'my-project.config/config" "#'my-project.db/conn"}}
 {:name "#'my-project.web.prelaunch/routes",
  :order 8,
  :status #{:started},
  :deps #{"#'my-project.web.forms.malli/coercer" "#'my-project.config/config" "#'my-project.db/conn"}}
 {:name "#'my-project.gateway/server", :order 9, :status #{:started}, :deps #{"#'my-project.config/config"}})

I was able to solve my issue by directly referencing the deps in ns I thought that mount would be ok with me referencing a state without explicitly naming it in the ns declaration. before my ns didn't have :refer or :rename

[my-project.web.storybook  :as storybook :refer [routes] :rename {routes storybook-routes}]
[my-project.web.backoffice :as backoffice :refer [routes] :rename {routes backoffice-routes}]
[my-project.web.prelaunch  :as prelaunch :refer [routes] :rename {routes prelaunch-routes}]

however, i still have the issue where when i reload a dep to gateway/server (backoffice/routes), gateway/server doesn't restart (no stop, no start). only the reloaded files state restarts. i would expect the states that depend on it to restart as well.

new state graph looks correct, but behaviour has not changed.

{:name "#'my-project.gateway/server",
 :order 9,
 :status #{:started},
 :deps #{"#'my-project.web.storybook/routes"
         "#'my-project.config/config"
         "#'my-project.web.prelaunch/routes"
         "#'my-project.web.backoffice/routes"}}