#953 MongoDB Support for Spring Cloud Task
MongoDB Support for Spring Cloud Task
Overview
This PR adds MongoDB repository support for Spring Cloud Task, following the same patterns as the existing JDBC implementation. Users can now choose MongoDB instead of relational databases for task execution storage.
Key Implementation
1. Auto-Configuration
File: MongoTaskAutoConfiguration.java
Automatically activates when MongoDB is configured:
- Condition: Requires
spring.cloud.task.repository-type=mongodb - Optional Dependency: Library compiles without MongoDB
spring:
cloud:
task:
repository-type: mongodb
2. Core Components
| Component | Description | File |
|---|---|---|
MongoTaskExecutionDao |
Task CRUD and sequence management | MongoTaskExecutionDao.java |
MongoTaskConfigurer |
TaskConfigurer implementation | MongoTaskConfigurer.java |
MongoTaskRepositoryInitializer |
Collection and index initialization | MongoTaskRepositoryInitializer.java |
MongoLockRepository |
Distributed lock for single-instance execution | MongoLockRepository.java |
3. MongoDB Collections
Task execution information is stored across 5 collections:
{tablePrefix}task_executions - Main execution info (ID, name, times, status)
{tablePrefix}task_execution_parameters - Execution parameters
{tablePrefix}task_batch_associations - Spring Batch Job associations
{tablePrefix}task_sequence - Auto-increment sequence
{tablePrefix}task_locks - Distributed locks
4. Key Features
- ✅ Atomic ID Generation: Thread-safe sequence using
findAndModify - ✅ Index Optimization: Compound indexes for query performance (taskName, startTime, endTime, etc.)
- ✅ Distributed Locking: MongoDB-based locks with TTL (auto-expiration)
- ✅ Transaction Support: Auto-detects and applies PlatformTransactionManager
- ✅ Immutability: TaskExecution's executionId is immutable after creation
Technical Implementation Details
1. Optional Dependency Pattern
MongoDB is declared as an optional dependency, allowing the library to work without MongoDB:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<optional>true</optional>
</dependency>
This requires TaskExecutionDaoFactoryBean to use reflection for MongoDB DAO creation:
// Object-type constructor to avoid compile-time dependency
public MongoTaskExecutionDao(Object mongoOperations, TaskProperties taskProperties) {
if (!(mongoOperations instanceof MongoOperations)) {
throw new IllegalArgumentException("...");
}
// ...
}
Pros:
- JDBC-only users don't need MongoDB dependencies
- Minimal dependency tree
Cons:
- Less type-safe (runtime check)
2. Sequence Management
MongoDB doesn't have auto-increment, so we use atomic findAndModify:
@Override
public long getNextExecutionId() {
Query query = new Query(Criteria.where("_id").is("task_seq"));
Update update = new Update().inc("sequence", 1);
FindAndModifyOptions options = new FindAndModifyOptions()
.upsert(true)
.returnNew(true);
TaskSequence sequence = mongoOperations.findAndModify(
query, update, options, TaskSequence.class,
sequenceCollection
);
return sequence.getSequence();
}
- Thread-safe: Processed atomically by MongoDB server
- Initial value: Starts at 0, returns 1 on first call (same as JDBC)
3. Distributed Lock Mechanism
MongoLockRepository implements Spring Integration's LockRegistry interface:
Key Improvements:
- ✅ Implemented
tryLock(long time, TimeUnit unit)timeout (was missing in initial implementation) - ✅ Automatic cleanup of expired locks
- ✅ Re-entrant (TTL extension for same client)
// Retry every 100ms, wait up to 5 seconds
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// Execute task
} finally {
lock.unlock();
}
}
Testing
Test Coverage
| Test Class | Description | Test Count |
|---|---|---|
MongoTaskExecutionDaoTests |
DAO CRUD and query tests | 49 |
MongoLockRepositoryTests |
Distributed lock and concurrency tests | 15 |
MongoTaskAutoConfigurationTests |
Auto-configuration condition tests | 7 |
MongoTaskConfigurerTests |
TaskConfigurer creation tests | 5 |
MongoTaskRepositoryInitializerTests |
Initialization and index tests | 8 |
Total: 84 tests passing
Features
- ✅ Extends
BaseTaskExecutionDaoTestCasesfor same test coverage as JDBC - ✅ Uses Testcontainers (real MongoDB 6.0)
- ✅ Includes concurrency tests
Running Tests
# All MongoDB tests
./mvnw test -pl spring-cloud-task-core -Dtest="Mongo*"
# Specific test class
./mvnw test -pl spring-cloud-task-core -Dtest=MongoTaskExecutionDaoTests
Usage Examples
Basic Configuration
spring:
data:
mongodb:
uri: mongodb://localhost:27017/taskdb
cloud:
task:
repository-type: mongodb
table-prefix: "TASK_"
Single Instance Execution (Distributed Lock)
spring:
cloud:
task:
repository-type: mongodb
single-instance-enabled: true
single-instance-lock-ttl: 30000 # 30 seconds
Application Code
@SpringBootApplication
@EnableTask
public class MyTaskApplication {
public static void main(String[] args) {
SpringApplication.run(MyTaskApplication.class, args);
}
@Bean
public CommandLineRunner taskRunner() {
return args -> {
System.out.println("Task execution info stored in MongoDB!");
// Task logic
};
}
}
Thank you so much for the contribution!!!!!! We'll schedule the addition for 5.1.x
@cppwfs I enjoyed the opportunity to work with Spring Cloud Task during this implementation! Please take a look and feel free to leave your feedback 😀