pdeva
pdeva

Reputation: 45451

Best way to handle read timeouts in Spring Data MongoDB

So from time to time we see exceptions like these:

java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at org.bson.io.Bits.readFully(Bits.java:48)
at org.bson.io.Bits.readFully(Bits.java:35)
at org.bson.io.Bits.readFully(Bits.java:30)
at com.mongodb.Response.<init>(Response.java:42)
at com.mongodb.DBPort$1.execute(DBPort.java:141)
at com.mongodb.DBPort$1.execute(DBPort.java:135)
at com.mongodb.DBPort.doOperation(DBPort.java:164)
at com.mongodb.DBPort.call(DBPort.java:135)
at com.mongodb.DBTCPConnector.innerCall(DBTCPConnector.java:292)
at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:271)
at com.mongodb.DBCollectionImpl.find(DBCollectionImpl.java:84)
at com.mongodb.DBCollectionImpl.find(DBCollectionImpl.java:66)
at com.mongodb.DBCollection.findOne(DBCollection.java:870)
at com.mongodb.DBCollection.findOne(DBCollection.java:844)
at com.mongodb.DBCollection.findOne(DBCollection.java:790)
at org.springframework.data.mongodb.core.MongoTemplate$FindOneCallback.doInCollection(MongoTemplate.java:2000)

Whats the best way to handle and recover from these in code? Do we need to put a 'retry' around each and every mongodb call?

Upvotes: 10

Views: 8207

Answers (5)

mihai.ciorobea
mihai.ciorobea

Reputation: 741

https://github.com/Netflix/Hystrix is your tool for handling dependecies.

Upvotes: 0

congsg2014
congsg2014

Reputation: 75

If i'm not mistaken, i think you need to config your properties like timeout or so when you try to build the connection or just prepare them well in connection pool. Or,you may just check your network or machine, and split your request-data by more times to reduce network trans time

Upvotes: 0

Rafal G.
Rafal G.

Reputation: 4432

If you want to approach timeouts (and related) problems not only for your MongoDB but also for any other external references then you should try Netflix's Hystrix (https://github.com/Netflix/Hystrix).

It is an awesome library that integrates nicely with RX and Asynchronous processing that becomes so much more popular lately.

Upvotes: 0

kamoor
kamoor

Reputation: 2939

You can use MongoClientOptions object to set different optional connection parameters. You are looking at setting heart beat frequency to make sure driver retry for connection. Also set socket time out to make sure it does not continue for too long.

  1. MinHeartbeatFrequency: In the event that the driver has to frequently re-check a server's availability, it will wait at least this long since the previous check to avoid wasted effort. The default value is 10ms.
  2. HeartbeatSocketTimeout: Timeout for heart beat check
  3. SocketTimeout: Time out for connection

Reference API

To avoid too much code duplication, optionally you can follow some pattern as given below. Basic idea is to avoid any database connection related configuration littered everywhere in the projects.

/**
 * This class is an abstraction for all mongo connection config
 **/
 @Component
 public class MongoConnection{

    MongoClient mongoClient = null;

    ...

   @PostConstruct
   public void init() throws Exception {
            // Please watch out for deprecated methods in new version of driver.
            mongoClient = new MongoClient(new ServerAddress(url, port), 
                            MongoClientOptions.builder()
                            .socketTimeout(3000)
                            .minHeartbeatFrequency(25)
                            .heartbeatSocketTimeout(3000)
                            .build());
            mongoDb = mongoClient.getDB(db);
        .....   
   }

   public DBCollection getCollection(String name) {
        return mongoDb.getCollection(name);
    }
   }

Now you can use MongoConnection in DAO-s

@Repository
public class ExampleDao{

  @Autowired
  MongoConnection mongoConnection;

  public void insert(BasicDBObject document) {
     mongoConnection.getCollection("example").insert(document);
  }  
}

You can also implement all the database operations inside MongoConnection to introduce some common functionality across the board. For example add logging for all "inserts"

Upvotes: 6

mavarazy
mavarazy

Reputation: 7735

One of the many options, to handle retry is Spring retry project

https://github.com/spring-projects/spring-retry

Which provides declarative retry support for Spring applications. This is basically Spring answer for this problem. It is used in Spring Batch, Spring Integration, Spring for Apache Hadoop (amongst others).

Upvotes: 0

Related Questions