Open wilkinsona opened 6 years ago
The confusion for us came because of two reasons One, we have been using Couchbase without issues, and when we migrated to MongoDB we had to exclude the autoconfigurer. That felt odd.
Two, how the Autoconfiguration starts and logs the MongoClient behauviour...
Note: whe use a logback logging configuration importing springs defaults
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
Imho, all Autoconfigurators for components depend on some mid-complex configuration should check for properties. Simple things or when a default config is a common thing like Gson or Jackson are fine that they only check for Beans.
Btw, the reason why we have a custom connector and do not expose a MongoClient to the Spring context is because we have a multitennacy platform that manages several connections at once. We load the configurations from a config-service and then initialize all our MongoClients inside a custom bean. That bean is the exposed, but not the clients.
Here's the error from the attachment:
2017-12-12 12:58:38.732 INFO [multitenancy-server,,,] 9520 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9040 (http)
2017-12-12 12:58:38.741 INFO [multitenancy-server,,,] 9520 --- [ main] c.e.e.m.MultitenancyServerApplication : Started MultitenancyServerApplication in 12.765 seconds (JVM running for 13.878)
2017-12-12 12:58:38.826 INFO [multitenancy-server,,,] 9520 --- [localhost:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.connection.SocketStream.open(SocketStream.java:62)
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:107)
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:111)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.mongodb.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:59)
at com.mongodb.connection.SocketStream.open(SocketStream.java:57)
... 3 common frames omitted
IMO, the main problem with the current situation is the inconsistency in behaviour across the different data stores for which auto-configuration is provided. The current behaviour when dependencies are available but no configuration is provided is described in the following table:
Store | Result |
---|---|
JDBC | Can't determine the driver class and fails to start. |
Cassandra | Tries to connect to localhost and fails to start. |
Couchbase | Auto-configuration backs off and application starts. |
Elasticsearch | Auto-configuration backs off and application starts. |
Mongo | Application starts but logs a ConnectException . Any calls to Mongo fail. |
Redis | Application starts cleanly. Any calls to Redis fail. |
Solr | Application starts cleanly. Any calls to Solr fail. |
These results were gathered from deliberately minimal applications that didn't attempt to autowire or use any components that may or may not have been auto-configured.
@mbhave made a good point about a knock-on effect of this inconsistency with respect to actuator and the health endpoint. The health responses are shown in the following table:
Store | Health |
---|---|
Couchbase | Up |
Elasticsearch | Up |
Mongo | Down |
Redis | Down |
Solr | Down |
The difference in health responses is determined by the auto-configuration either backing off or "successfully" configuring beans that can't actually communicate with the data store.
Wondering if this should be in the backlog?
It'd be nice to tackle it in 2.1 if we can.
I just wanted to add that apart from different connectivity behaviour for different DBs, applications can also react very differently to a specific DB depending on applications content(business logic, configurations), which is sometimes very confusing.
Let me describe it with one example: I have 2 mongo db-based apps. I'm starting them to make sure everything is Ok. However, I forgot that I haven't started mongo server yet. And yet one app will fail to start and another one will print a connection error stacktrace but keep on running. It took me a while to figure out that the one that fails had a @Document with @Index in it, while the other one didn't. So, by just adding/deleting @Index annotation I can significantly impact the way Spring Boot react to mongo DB availability. It is reproducible on our apps but it can also be easily reproduced on the very minimal app with zero business logic or customization. The entity is as follows:
@Document(collection = "domain")
public class Domain {
@Id
private long id;
//If I leave it like this, an app fails to start, if I comment the next line, it starts up successfully.
@Indexed(unique = true)
private String domain;
private boolean displayAds;
}
That's all the code that is needed to reproduce it. This class might not be used anywhere at all. I haven't exposed it into any services or controllers. A properties file is also empty. It's as skinny as it gets. And yet, even with this minimal configuration I can reproduce a very confusing behavioral pattern that I'd prefer to be fixed.
We are using Reactive Redis to cache web-client response.If Redis server is up and running application works fine.But App start up is failing ,if we stop redis. Expected behavior is app should still go ahead and start even though redis connection fails.Does spring handles connection exception?or do we have to handle this kind of exceptions?
Neo4j is also affected in a similar way. An app will fail to start when Neo4j can't be reached. #23707 contains some details, including failures both with and without Actuator.
This was raised as part of a discussion on Twitter. The specific example given is Mongo which connects to
localhost
when it's on the classpath and Couchbase which doesn't connect to anything until your configure at least one bootstrap host.There may well be good reasons for the apparent inconsistency, but it appears to be causing some confusion. It would be nice to align the behaviour across data stores if we can. If there are good reasons not to do that, it would be nice to see if we can somehow make the varying behaviour less surprising.