mount is an alternative to the [component](https://github.com/stuartsierra/component) approach with notable [differences](doc/differences-from-component.md#differences-from-component).
Whether it is in REPL or during testing, it is often useful to start an application _without_ certain states. These can be queue listeners that are not needed at REPL time, or a subset of an application to test.
The `start-without` function can do just that:
```clojure
(mount/start-without #'app.feeds/feed-listener
#'app/nrepl)
```
which will start an application without starting `feed-listener` and `nrepl` states.
Here is an [example](test/check/start_without_test.clj) test that excludes Datomic connection and nREPL from an application on start.
## Swapping Alternate Implementations
During testing it is often very useful to mock/stub certain states. For example runnig a test against an in memory database vs. the real one, running with a publisher that publishes to a test core.async channel vs. the real remote queue, etc.
`start-with` takes a map of states with their substitutes. For example `#'app.nyse/db` here is the real deal (remote) DB that is being substituted with `#'app.test/test-db` state, which could be anything, a map, an in memory DB, etc.
One thing to note, whenever
```clojure
(mount/stop)
```
is run after `start-with`, it rolls back to an original "state of states", i.e. `#'app.nyse/db` is `#'app.nyse/db` again. So a subsequent calls to `(mount/start)` or even to `(mount/start-with {something else})` will start from a clean slate.
Here is an [example](test/check/start_with_test.clj) test that starts an app with mocking Datomic connection and nREPL.
Calling `(mount/stop)` will stop all the application states. In case everything needs to be stopped _besides certain ones_, it can be done with `(mount/stop-except)`.
Here is an example of restarting the application without bringing down `#'app.www/nyse-app`:
```clojure
dev=> (mount/start)
14:34:10.813 [nREPL-worker-0] INFO mount.core - >> starting.. app-config
14:34:10.814 [nREPL-worker-0] INFO mount.core - >> starting.. conn
14:34:10.814 [nREPL-worker-0] INFO app.db - creating a connection to datomic: datomic:mem://mount
14:34:10.838 [nREPL-worker-0] INFO mount.core - >> starting.. nyse-app
14:34:10.843 [nREPL-worker-0] DEBUG o.e.j.u.component.AbstractLifeCycle - STARTED SelectChannelConnector@0.0.0.0:4242
14:34:10.843 [nREPL-worker-0] DEBUG o.e.j.u.component.AbstractLifeCycle - STARTED org.eclipse.jetty.server.Server@194f37af
14:34:10.844 [nREPL-worker-0] INFO mount.core - >> starting.. nrepl
:started
dev=> (mount/stop-except #'app.www/nyse-app)
14:34:47.766 [nREPL-worker-0] INFO mount.core - <<stopping..nrepl
14:34:47.766 [nREPL-worker-0] INFO mount.core - <<stopping..conn
14:34:47.766 [nREPL-worker-0] INFO app.db - disconnecting from datomic:mem://mount
14:34:47.766 [nREPL-worker-0] INFO mount.core - <<stopping..app-config
:stopped
dev=>
dev=> (mount/start)
14:34:58.673 [nREPL-worker-0] INFO mount.core - >> starting.. app-config
14:34:58.674 [nREPL-worker-0] INFO app.config - loading config from test/resources/config.edn
14:34:58.674 [nREPL-worker-0] INFO mount.core - >> starting.. conn
14:34:58.674 [nREPL-worker-0] INFO app.db - creating a connection to datomic: datomic:mem://mount
14:34:58.693 [nREPL-worker-0] INFO mount.core - >> starting.. nrepl
:started
```
Notice that the `nyse-app` is not started the second time (hence no more accidental `java.net.BindException: Address already in use`). It is already up and running.
## Suspending and Resuming
Besides starting and stopping states can also be suspended and resumed. While this is not needed most of the time, it does comes really handy _when_ this need is there. For example:
* while working in REPL, you only want to truly restart a web server/queue listener/db connection _iff_ something changed, all other times `(mount/stop)` / `(mount/start)` or `(reset)` is called, these states should not be restarted. This might have to do with time to connect / bound ports / connection timeouts, etc..
* when taking an application out of rotation in a data center, and then phasing it back in, it might be handy to still keep it _up_, but suspend all the client / novelty facing components in between.
and some other use cases.
### Suspendable Lifecycle
In additiong to `start` / `stop` functions, a state can also have `resume` and, if needed, `suspend` ones:
```clojure
(defstate web-server :start (start-server ...)
:resume (resume-server ...)
:stop (stop-server ...))
```
`suspend` function is optional. Combining this with [(mount/stop-except)](#stop-an-application-except-certain-states), can result in an interesting restart behavior where everything is restared, but this `web-server` is _resumed_ instead (in this case `#'app.www/nyse-app` is an example of the above `web-server`):
```clojure
dev=> (mount/stop-except #'app.www/nyse-app)
14:44:33.991 [nREPL-worker-1] INFO mount.core - <<stopping..nrepl
14:44:33.992 [nREPL-worker-1] INFO mount.core - <<stopping..conn
14:44:33.992 [nREPL-worker-1] INFO app.db - disconnecting from datomic:mem://mount
14:44:33.992 [nREPL-worker-1] INFO mount.core - <<stopping..app-config
:stopped
dev=>
dev=> (mount/suspend)
14:44:52.467 [nREPL-worker-1] INFO mount.core - >> suspending.. nyse-app
:suspended
dev=>
dev=> (mount/start)
14:45:00.297 [nREPL-worker-1] INFO mount.core - >> starting.. app-config
14:45:00.297 [nREPL-worker-1] INFO mount.core - >> starting.. conn
14:45:00.298 [nREPL-worker-1] INFO app.db - creating a connection to datomic: datomic:mem://mount
14:45:00.315 [nREPL-worker-1] INFO mount.core - >> resuming.. nyse-app
14:45:00.316 [nREPL-worker-1] INFO mount.core - >> starting.. nrepl
:started
```
Notice `>> resuming.. nyse-app`, which in [this case](https://github.com/tolitius/mount/blob/suspendable/test/app/www.clj#L32) just recreates Datomic schema vs. doing that _and_ starting the actual web server.
### Plugging into (reset)
In case `tools.namespace` is used, this lifecycle can be easily hooked up with `dev.clj`:
```clojure
(defn start []
(mount/start))
(defn stop []
(mount/suspend)
(mount/stop-except #'app.www/nyse-app))
(defn reset []
(stop)
(tn/refresh :after 'dev/start))
```
### Suspendable Example Application
An [example application](https://github.com/tolitius/mount/tree/suspendable/test/app) with a suspendable web server and `dev.clj` lives in the `suspendable` branch. You can clone mount and try it out: