or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

annotation-config.mdaot.mdcaching.mdcontext-lifecycle.mdevents.mdformatting.mdi18n.mdindex.mdjmx.mdresilience.mdscheduling.mdstereotypes.mdvalidation.md
tile.json

scheduling.mddocs/

Task Scheduling and Async Execution

@EnableScheduling & @EnableAsync

@Configuration
@EnableScheduling
@EnableAsync
public class SchedulingConfig {

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);
        scheduler.setThreadNamePrefix("scheduled-");
        scheduler.setAwaitTerminationSeconds(60);
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.initialize();
        return scheduler;
    }

    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }
}

@Scheduled

@Service
public class ScheduledTasks {

    // Fixed rate - execute every 5 seconds
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() {}

    // Fixed delay - 3 seconds after completion
    @Scheduled(fixedDelay = 3000)
    public void fixedDelayTask() {}

    // Initial delay before first execution
    @Scheduled(fixedRate = 5000, initialDelay = 10000)
    public void delayedStart() {}

    // Cron expressions
    @Scheduled(cron = "0 0 * * * *")  // Every hour
    public void hourlyTask() {}

    @Scheduled(cron = "0 0 2 * * *", zone = "America/New_York")  // Daily at 2 AM EST
    public void dailyTask() {}

    @Scheduled(cron = "0 */5 * * * *")  // Every 5 minutes
    public void everyFiveMinutes() {}

    // Externalized configuration
    @Scheduled(fixedRateString = "${task.rate:5000}",
               initialDelayString = "${task.delay:2000}")
    public void configurableTask() {}

    // Duration format (Spring 5.3+)
    @Scheduled(fixedRateString = "PT5S")  // ISO-8601 duration
    public void durationTask() {}
}

Cron Format: second minute hour day-of-month month day-of-week

@Async

@Service
public class AsyncService {

    // Void return
    @Async
    public void asyncVoidMethod() {
        // Executes asynchronously
    }

    // CompletableFuture return
    @Async
    public CompletableFuture<String> asyncWithResult() {
        return CompletableFuture.completedFuture("result");
    }

    // Future return
    @Async
    public Future<Integer> asyncComputation() {
        return new AsyncResult<>(42);
    }

    // Specific executor
    @Async("ioExecutor")
    public void asyncIoOperation() {}
}

// Caller code
CompletableFuture<String> future = service.asyncWithResult();
future.thenAccept(result -> System.out.println(result));

TaskScheduler

@Service
public class ProgrammaticScheduler {

    @Autowired
    private TaskScheduler taskScheduler;

    public void scheduleTask() {
        // One-time execution
        taskScheduler.schedule(
            () -> System.out.println("Task executed"),
            Instant.now().plusSeconds(5)
        );

        // Fixed rate
        taskScheduler.scheduleAtFixedRate(
            () -> System.out.println("Periodic task"),
            Duration.ofSeconds(30)
        );

        // Fixed delay
        taskScheduler.scheduleWithFixedDelay(
            () -> System.out.println("Delayed task"),
            Duration.ofSeconds(10)
        );

        // With custom trigger
        CronTrigger trigger = new CronTrigger("0 0 9 * * MON-FRI");
        taskScheduler.schedule(
            () -> System.out.println("Weekday task"),
            trigger
        );
    }
}

Custom Trigger

public class AdaptiveTrigger implements Trigger {

    private final Duration minDelay;
    private final Duration maxDelay;

    public AdaptiveTrigger(Duration minDelay, Duration maxDelay) {
        this.minDelay = minDelay;
        this.maxDelay = maxDelay;
    }

    @Override
    public Instant nextExecution(TriggerContext context) {
        Instant lastCompletion = context.lastCompletion();
        if (lastCompletion == null) {
            return Instant.now().plus(minDelay);
        }

        // Adaptive delay based on execution time
        Duration executionTime = Duration.between(
            context.lastActualExecution(),
            lastCompletion
        );

        Duration delay = executionTime.multipliedBy(2);
        if (delay.compareTo(minDelay) < 0) delay = minDelay;
        if (delay.compareTo(maxDelay) > 0) delay = maxDelay;

        return lastCompletion.plus(delay);
    }
}

SchedulingConfigurer

@Configuration
@EnableScheduling
public class DynamicSchedulingConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {
        registrar.setScheduler(taskScheduler());

        // Register cron task
        registrar.addCronTask(
            () -> System.out.println("Cron task"),
            "0 0 * * * *"
        );

        // Register fixed-rate task
        registrar.addFixedRateTask(
            () -> System.out.println("Fixed-rate task"),
            Duration.ofSeconds(5).toMillis()
        );

        // Register trigger-based task
        registrar.addTriggerTask(
            () -> System.out.println("Trigger task"),
            new PeriodicTrigger(Duration.ofSeconds(30))
        );
    }

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);
        scheduler.initialize();
        return scheduler;
    }
}

AsyncConfigurer

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(15);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            System.err.println("Exception in " + method.getName() + ": " + ex.getMessage());
        };
    }
}