Skip to content

Conversation

belljun3395
Copy link

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 BaseTaskExecutionDaoTestCases for 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
        };
    }
}

@cppwfs cppwfs added this to the 5.1.x milestone Sep 30, 2025
@cppwfs
Copy link
Collaborator

cppwfs commented Sep 30, 2025

Thank you so much for the contribution!!!!!!
We'll schedule the addition for 5.1.x

@belljun3395
Copy link
Author

@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 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants