
Fixing Spring Boot's MongoDB healthcheck for Cosmos DB
- February 5th, 2025
- 3 minute read
- Spring Spring boot Azure MongoDB
Background
If you’re using Azure Cosmos DB for MongoDB and you’ve upgraded to Spring Boot 3.2.7 or higher recently, you might have noticed it: the Spring Boot health actuator no longer works. The error you’ll see is something like this:
{
"status": "DOWN",
"details": {
"error": "org.springframework.dao.InvalidDataAccessApiUsageException: Command failed with error 115 (CommandNotSupported): 'Command hello not supported.' on server my-cosmosdb.mongo.cosmos.azure.com:10255. The full response is {\"ok\": 0.0, \"errmsg\": \"Command hello not supported.\", \"code\": 115, \"codeName\": \"CommandNotSupported\"}"
}
}
In addition, you’ll see a a stacktrace containing a message lik this:
Caused by: com.mongodb.MongoCommandException: Command failed with error 115 (CommandNotSupported): 'Command hello not supported.' on server my-cosmosdb.mongo.cosmos.azure.com:10255. The full response is {"ok": 0.0, "errmsg": "Command hello not supported.", "code": 115, "codeName": "CommandNotSupported"}
The reason you’re suddenly see this exception is because in Spring Boot 3.2.7, the command to check the MongoDB health has been changed.
Previously, it used the db.runCommand({isMaster: 1})
command (documentation).
However, this check was proven to be flaky, because the isMaster
command is not a part of the stable API and was deprecated in MongoDB 4.4.2 (documentation).
This means that if strict mode was configured, the previous actuator would fail.
So, since Spring Boot 3.2.7, the previous check was replaced by db.runCommand({hello: 1})
, which was introduced in MongoDB 4.4.2 and later backported to older MongoDB versions as well (see issue).
Normally, this shouldn’t be a problem, since Cosmos DB also included support for the hello
command in the MongoDB support for 4.0 and later (documentation).
The problem however is that this support is only partially implemented. The following command will work on both MongoDB as on Cosmos DB:
db.hello(); // Works on both MongoDB and Cosmos DB
The next command will however only work on MongoDB:
db.runCommand({hello: 1}); // Works on MongoDB, but fails on Cosmos DB
Summarized, this means that MongoDB for Cosmos DB is not compliant with the official MongoDB specification.
The solution
The solution is that if you’re using Spring Boot 3.2.7 or higher, you cannot rely on the builtin health indicator. This means that you at least need to disable it by configuring the following property:
management.health.mongo.enabled=false
In addition, you can implement your own custom health indicator.
However, since executing shell commands through the Java driver isn’t very easy and isMaster
is deprecated, we should look for an alternative database command to validate your MongoDB connection.
The command I chose is buildInfo
, which is both supported by MongoDB (documentation) as by Cosmos DB (documentation).
To implement this health indicator, you can write something like this:
@Component
public class MongoHealthIndicator extends AbstractHealthIndicator {
private final MongoTemplate mongoTemplate;
public MongoHealthIndicator(MongoTemplate mongoTemplate) {
super("MongoDB health check failed");
Assert.notNull(mongoTemplate, "'mongoTemplate' must not be null");
this.mongoTemplate = mongoTemplate;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Document result = this.mongoTemplate.executeCommand("{ buildInfo: 1 }");
builder.up();
}
}
Alternatively, if you use the reactive version of Spring Data MongoDB, you need to use the ReactiveMongoTemplate
and the AbstractReactiveHealthIndicator
class and then you can write a health indicator like this:
@Component
public class MongoReactiveHealthIndicator extends AbstractHealthIndicator {
private final ReactiveMongoTemplate reactiveMongoTemplate;
public MongoReactiveHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) {
super("MongoDB health check failed");
Assert.notNull(reactiveMongoTemplate, "'reactiveMongoTemplate' must not be null");
this.reactiveMongoTemplate = reactiveMongoTemplate;
}
@Override
protected Mono<Health> doHealthCheck(Health.Builder builder) throws Exception {
return mongoTemplate
.executeCommand("{ buildInfo: 1 }")
.map(document -> builder.up().build());
}
}
Note, these indicators are based on the existing MongoHealthIndicator
and MongoReactiveHealthIndicator
.
After that, if you launch your application, you should see the new health indicator working properly.