Comments (7)
The above use case is not limited to the components restarting themselves. For example, a watchdog component that checks the system health should be able to restart parts of the system as needed. Thus, such components must be able to access the system var somehow. How would you go about implementing this?
from integrant.
There are two broad solutions to this.
One solution is that the component itself can take care of restarting connections. A common example of this is a SQL connection pool. If a connection is broken, the pool will give the user a new connection. All I/O connections should be wrapped in boundaries anyway, both to allow easier testing and to loosen the coupling between the connection and the rest of your code.
Another solution is to introduce a watchdog component and pass in the components you want to watch as references. For example:
{:example/server {:port 8080}
:example/watchdog #{#ig/ref :example/server}}
Perhaps the server adheres to a protocol that allows it to be restarted.
Alternatively, and usually preferably, this can be done at a system level. If something goes wrong and we lose a connection or the server goes down, we can just log the problem then exit the application with a failure code. If we're using something like systemd to manage our application, it will be restarted automatically.
from integrant.
All I/O connections should be wrapped in boundaries anyway,
I guess this is what I was missing. I was exposing too much of the component to its children.
Are there reasonably complete examples of systems built on integrant
somewhere? Something like those in system/examples
? I have never used component
nor mount
, so I am having a bit of a struggle on the "grand-design" side of things.
from integrant.
{:example/server {:port 8080} :example/watchdog #{#ig/ref :example/server}}
But in order for this to work I need to design the :example/server
as mutable object such that I could restart it in-place. Is this what you meant?
from integrant.
Ah, sorry, I should have explained further. Boundaries are a Duct concept, and as I've been writing a lot of Duct recently, and the new Duct alpha makes heavy use of Integrant, I forgot I was replying to an issue on the Integrant repository, and not the Duct repository.
So let me start again 😃 .
I've found it good practice to avoid tightly coupling my functional code with the code that handles I/O. Some languages, like Haskell, enforce this distinction; in Clojure we have to have a little more self-discipline.
A websocket is a little complex for an example, because we need to handle channel closing, errors, and so forth. Instead, consider a SQL connection pool, which already does all those things for us. We could interact directly with the connection:
(defn get-user [spec email]
(jdbc/query spec ["SELECT * FROM users WHERE email = ?" email]))
(defmethod ig/init-key :database/sql [_ options]
{:datasource (db/connect-pool options)})
But I've found it's useful to add a layer inbetween to loosen the coupling:
(defprotocol Users
(get-user [db email]))
(defrecord DatabaseBoundary [spec]
Users
(get-user [_ email]
(jdbc/query spec ["SELECT * FROM users WHERE email = ?" email])))
(defmethod ig/init-key :database/sql [_ options]
(->DatabaseBoundary {:datasource (db/connect-pool options)}))
In this example, the DatabaseBoundary
record does very little, but it still provides us with a way of mocking out the database when required. In a more complex example, we can manage connections and reconnections, and use the protocol to abstract that away.
from integrant.
But in order for this to work I need to design the
:example/server
as mutable object such that I could restart it in-place. Is this what you meant?
The :example/watchdog
key would need some internal mutation, but not necessarily the :example/server
key, so long as no other keys depended on the server.
However, now that I've thought about it a little further, I don't think I'd recommend a :example/watchdog
approach. In general, I think the safest option is to stop the system when something unexpected happens. Checking the system's health shouldn't be necessary if we kill it off the moment it looks sick.
For connections and so forth, we can give the component itself a connection pool, or some way of restarting the connection when it's dropped. This is a common problem, so there may be libraries out there to simplify this.
from integrant.
Boundaries are a Duct concept,
Yes. I read your note on boundaries here and will try to follow the advice from now on.
Checking the system's health shouldn't be necessary if we kill it off the moment it looks sick.
I have multiple websockets open (listening for transactions) and restarting the full application on every websocket disconnect is really not an option.
This is a common problem, so there may be libraries out there to simplify this.
I am using manifold
which provides on-close
callback but AFAICS has no provision for reconnection. So for now I will simply keep the connection in an atom or a mutable deftype and reset it when needed.
Thank you for all the input!
from integrant.
Related Issues (20)
- Would you consider an integrant2 to support extensible build steps? HOT 10
- Why does resume halt unspecified system keys? HOT 4
- Support usage in Babashka environments HOT 20
- #{:idea} Pass the spec validations step on all defined states before calling init-key. HOT 1
- is it possible to access a component after it's init-key, but before it gets passed to the next key that depends on it? HOT 2
- Enter Integrant Video
- Add support for custom assertf definitions HOT 2
- Question: Extract "validation keys" logic from core/build implementation HOT 4
- Feature request: pre-init hook
- No method in multimethod 'init-key' for dispatch value HOT 2
- #ig/ref should allow for deep references HOT 1
- Uninitialized/literal configs HOT 1
- Tests don't run with 1.11 due to clojure.test/run-test already being defined HOT 1
- Feature proposal: expand-key HOT 2
- Any way to add constant key in `edn`? HOT 2
- Unable to access Presentations(Enter Integrant) HOT 3
- Perhaps use metadata as an alternative to resolve-key? HOT 2
- Refs/Refsets not preserved after expansion HOT 1
- Convenience tag to add methods for static keys HOT 1
- Is there a way to analyze components at the repl with their config resolved ? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from integrant.