31

I get this error on a find call (default Java Driver) after a period of inactivity. I tried to add a manual heartbeat (writing to a capped collection), but it didn't help. I only get the issue while being connected to an instance on compose (i.e. not in a local context).

MongoDB version is 3.2.8, latest driver (3.3), using Java 8.

Any idea ?

Rhangaun
  • 1,430
  • 2
  • 15
  • 34
  • I found out that the `isSocketKeepAlive` flag of the `MongoClientOptions` is `false` by default, I changed it to true and I'm now waiting to see if I get the error again. – Rhangaun Sep 07 '16 at 11:44
  • 8
    unfortunatly, with .socketKeepAlive(true), we also get this error, my drive version is 3.0.4 – Feng Sep 14 '16 at 07:58
  • could you find the reason at last? I face to this error now – Narges Sep 20 '17 at 11:22
  • Can you check how many connections you have available? Run this from the mongo shell: `db.serverStatus().connections` { "current" : 204, "available" : 0, "totalCreated" : NumberLong(931) } – Eric Clack Jan 15 '18 at 10:42
  • if you are here for this error and java socket is closed take a look at: https://www.mongodb.com/community/forums/t/prematurely-reached-end-of-stream/139733 – AbdurrahmanY Jul 25 '22 at 15:26

7 Answers7

26

I found it in some documentation:

For long running applications, it is often prudent to enable "keepAlive" with a number of milliseconds. Without it, after some period of time you may start to see "connection closed" errors for what seems like no reason.

Check if this helps. When you connect to mongoDB you can pass socket options to it. I am from node background we use following options to keep it alive.

server: {
        socketOptions: {
            keepAlive: 100,
            connectTimeoutMS: 30000
        }
    }

Hope this helps!!

Sachin
  • 2,912
  • 16
  • 25
  • 4
    It has been deprecated as it's now defaults to true. So it's always enabled: https://mongodb.github.io/mongo-java-driver/3.6/javadoc/com/mongodb/MongoClientOptions.Builder.html#socketKeepAlive-boolean- – streetturtle Nov 20 '19 at 19:07
7

I solve this problem by set sslEnabled to true,code sample:

@Bean
public MongoClient mongoClient() {
    List<ServerAddress> saList = new ArrayList<>();
    saList.add(new ServerAddress("cluster0-shard-00-00-75shm.gcp.mongodb.net", 27017));
    saList.add(new ServerAddress("cluster0-shard-00-01-75shm.gcp.mongodb.net", 27017));
    saList.add(new ServerAddress("cluster0-shard-00-02-75shm.gcp.mongodb.net", 27017));

    char[] pwd =  "password".toCharArray();
    MongoCredential credential = MongoCredential.createCredential("username", "admin", pwd);

    //set sslEnabled to true here
    MongoClientOptions options = MongoClientOptions.builder()
            .readPreference(ReadPreference.primaryPreferred())
            .retryWrites(true)
            .requiredReplicaSetName("Cluster0-shard-0")
            .maxConnectionIdleTime(6000)
            .sslEnabled(true)
            .build();

    MongoClient mongoClient = new MongoClient(saList, credential, options);     
    return mongoClient;
}

Addition: my client jar is org.mongodb.mongodb-driver 3.6.4,server is mongodb atlas M0 3.6.6 on GCP

iengchen
  • 341
  • 4
  • 9
  • 3
    if your SSL was enabled, then where were the certificates? and where is the code for the same in above piece of code. – Ankur Soni Sep 20 '18 at 09:09
5

I agree with Rhangaun's answer here is my solution in code of JAVA:

    public static DB getMongoDB() {

        MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
        //build the connection options  
        builder.maxConnectionIdleTime(60000);//set the max wait time in (ms)
        MongoClientOptions opts = builder.build();
        
    
        char[] password2 = "mypassword".toCharArray();
        
        MongoCredential credential2 = MongoCredential.createCredential("username", "databasename",password2);
        
       
        //add your option to the connection 

        MongoClient mongoClient = new MongoClient(new ServerAddress("server ip",27017), Arrays.asList(credential2),opts);
        //use your database 
        cachedDb = mongoClient.getDB("databasename");
        
    return cachedDb;

}

Here is my research link:http://3t.io/blog/how-to-prevent-your-connection-from-dropping-with-hosted-mongodb-instances/

Hope it helps you.

1000111
  • 13,169
  • 2
  • 28
  • 37
Daqian
  • 84
  • 4
  • I was using this constructor to build connection but always get exception: MongoClient mongoClient = new MongoClient(new ServerAddress("203.11.83.230",27017), Arrays.asList(credential2)) I changed to differnet one with MongoClientOptions everything works fine for me – Daqian Sep 16 '16 at 05:57
5

This worked for me in spring boot and cloud based mongo (Atlas clustered instances).

Edit application.properties like this:

spring.data.mongodb.uri = mongodb+srv://username:password@solarsystem-1tpu0.mongodb.net/dbname

For regular mongo instances (non-clustered) use this:

spring.data.mongodb.uri = mongodb://username:password@solarsystem-shard-00-00-1tpu0.mongodb.net:27017,hostname2:27017/dbname?ssl=true
Community
  • 1
  • 1
julianm
  • 2,393
  • 1
  • 23
  • 24
0

To me it was a whole different issue - I was using mongo-java-server with Fongo and ended up getting this error. Turns out that old versions of it are not compatible with FieldType.DECIMAL128 conversions.

Updating it to the latest one (1.36.0 currently) fixed the issue for me.

maaw
  • 1,276
  • 13
  • 13
0

The problem is that Mongodb end the connection. You need to increase the timeout of the Mongodb Driver here is an example code.

 MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
    //build the connection options
    builder.maxConnectionIdleTime(86400000);//set the max wait time in (ms)
    MongoClientOptions opts = builder.build();




    final Morphia morphia = new Morphia();


    morphia.mapPackage("com.java.code");


    final String hostURL = "host_url";
            

    MongoCredential  credential = MongoCredential.createCredential("username","database","Password".toCharArray()); 

    ServerAddress address = new ServerAddress(hostURL);


    List<MongoCredential> credentialList = new ArrayList<>();
    credentialList.add(credential);


   final MongoClient client = new MongoClient(address,credentialList,opts);




    // create the Datastore connecting to the default port on the local host
    datastore  = morphia.createDatastore(client,"datastore");
Jose Salas
  • 55
  • 5
0

I was able to fix it after taking two steps.

First one:
Preparation of the appropriate MongoClientSettings object containing the key settings for our Mongo client.

private MongoClientSettings getMongoClientSettings() {
    return MongoClientSettings.builder()
        .retryWrites(true)
        .applyToConnectionPoolSettings(poolSettings -> poolSettings
                .minSize(5)
                .maxSize(300)
                .maxConnectionIdleTime(0, TimeUnit.MILLISECONDS))
        .applyToSocketSettings(socketSettings -> socketSettings
                .connectTimeout(1, TimeUnit.MINUTES)
                .readTimeout(1, TimeUnit.MINUTES))
        .build();
}

maxConnectionIdleTime – the maximum time a connection can be unused. A zero value indicates no limit to the idle time.

maxSize - The maximum number of connections allowed. Those connections will be kept in the pool when idle. Once the pool is exhausted, any operation requiring a connection will block waiting for an available connection. Default is 100

minSize - The minimum number of connections. Those connections will be kept in the pool when idle, and the pool will ensure that it contains at least this minimum number. Default is 0

Second one:
Increasing the default timeout in application.properties / application.yaml file (or the one you already have)

mongodb:
 database: your_db_name
 authDatabase: admin
 config:
   enabled: true
   write:
     writeConcern:
       isMajority: true
     timeout:
       milliseconds: 100000

Check it out and it should work :)

Oskarro
  • 323
  • 2
  • 9