MongoDB: server not selected using ReadPreferenceServerSelector
I am recently using the async java mongodb driver which was recently released. I am writing some simple test codes that:
MongoClient mongoClient = MongoClients.create();
System.out.println("database has been connected!");
SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() {
@Override
public void onResult(final Void result, final Throwable t) {
System.out.println("Operation Finished!");
}
};
mongoClient.listDatabaseNames().forEach(new Block<String>() {
@Override
public void apply(final String s) {
System.out.println(s);
}
}, callbackWhenFinished);
however the callback function is not called, the console output is:
Apr 18, 2015 10:50:27 AM com.mongb.diagnostics.logging.JULLogger log message: Cluster created with settings {hosts = [localhost: 27017], mode = SINGLE, requiredClusterType = UNKNOWN, serverSelectionTimeout = '30000 ms', maxWaitQueueSize = 500}
the database has been connected! April 18, 2015 10:50:28 AM com.mongb.diagnostics.logging.JULLogger log message: No server selected by ReadPreferenceServerSelector {readPreference = primary} from cluster description ClusterDescription {type = UNKNOWN, connectionMode = SINGLE, all = [ServerDescription {address = localhost: 27017, type = UNKNOWN, state = CONNECTING}]}. Wait 30,000ms before shutdown time
So you can see that the callback function is not called. Does anyone know why?
source to share
The short answer is your answer will be called eventually.
For a long answer, let's work through your code:
MongoClient mongoClient = MongoClients.create();
System.out.println("database has been connected!");
MongoClient
does not block waiting for a connection to MongoDB in the background that tries to connect the internal connection pool. From your logs, I can see that you have a default of serverSelectionTimeout
30000ms.
In the next step you do println
, which is immediately outputted so that "the database is connected!". printed independently.
Finally, you call listDatabaseNames()
, but it's not clear if there is anyone waiting for the callback to be called. If you add a latch, then wait for a response, then you will see that the callback is called, for example:
System.out.println("======= Start =======");
MongoClient mongoClient = MongoClients.create();
final CountDownLatch latch = new CountDownLatch(1);
SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() {
@Override
public void onResult(final Void result, final Throwable t) {
System.out.println("Operation Finished!");
if (t != null) {
System.out.println("listDatabaseNames() errored: " + t.getMessage());
}
latch.countDown();
}
};
mongoClient.listDatabaseNames().forEach(new Block<String>() {
@Override
public void apply(final String s) {
System.out.println(s);
}
}, callbackWhenFinished);
latch.await();
// close resources
mongoClient.close();
System.out.println("======= Finish =======");
Now, using the we latch await()
until the callback is called, we should now see one of two things:
-
No MongoDB available. Eventually it will call the callback and print out the error message. He will wait for the time to run out
serverSelectionTimeout
. -
MongoDB available. It will eventually connect, for each database, it will apply
Block
and print the name of the database, and then finally call the callback to complete.
source to share
I think you should close the MongoClient object every time in the finally clause. The same problem came up for me, and when I closed the connection on the command line, I saw that many connections were open.
Try something like this (I'm using mongodb 3.0.7 and mongo-java-driver 3.1.0):
package com.mkyong.core;
import org.bson.Document;
import org.junit.Test;
import com.mongodb.Block;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoDatabase;
/**
* Unit test for simple App.
*/
public class AppTest {
@Test
public void firstTest() throws Exception {
MongoClient mongoClient = null;
try {
mongoClient = new MongoClient("127.0.0.1", 27017);
MongoDatabase db = mongoClient.getDatabase("census");
FindIterable<Document> iterable = db.getCollection("states").find();
iterable.forEach(new Block<Document>() {
@Override
public void apply(final Document document) {
System.out.println(document);
}
});
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
mongoClient.close();
} catch (Exception e2) {
}
}
}
}
With that, I could use my connection without any problem.
source to share