Class RoundRobinRetryScheduler
java.lang.Object
com.broadleafcommerce.common.messaging.notification.RoundRobinRetryScheduler
- All Implemented Interfaces:
org.springframework.beans.factory.Aware,org.springframework.context.ApplicationEventPublisherAware
public class RoundRobinRetryScheduler
extends Object
implements org.springframework.context.ApplicationEventPublisherAware
A specialized scheduler designed to manage the execution of multiple
RetryHandler
instances in a fair, round-robin fashion using a fixed-size thread pool.
Problem Statement:
In a system with many distinct RetryHandler instances (often one per repository/message
type combination), relying on individual threads or standard thread pools can lead to two main
issues:
- Resource Exhaustion: Creating a dedicated thread or scheduler for each handler scales poorly as the number of handlers grows.
- Starvation / Unfairness: If handlers share a common thread pool, a "noisy" handler (one with a very short retry interval or long processing time) can flood the task queue, preventing other handlers from getting CPU time.
Solution:
This scheduler addresses these concerns by decoupling the scheduling of tasks from their
execution.
- Fixed Resource Usage: It uses a single
ThreadPoolTaskExecutorwith a fixed maximum pool size (configurable via properties). This puts a hard cap on the number of concurrent retry threads, regardless of how many handlers are registered. - Fairness via Round-Robin: A lightweight "heartbeat" thread runs periodically (e.g., every 100ms) to check for ready handlers. It iterates through the registered handlers in a round-robin order. If a handler is ready to run (its interval has elapsed) and is not currently running, it is submitted to the worker pool.
- No Monopolization: Because the scheduler iterates through the list and only submits one task per handler at a time, a single handler cannot fill the worker pool with its own tasks. Even if a handler is ready to run every 1ms, the scheduler will visit all other handlers before considering it again.
- Non-Blocking: If the worker pool is full, the scheduler simply skips the current cycle and tries again on the next heartbeat, ensuring that the scheduling logic itself never blocks.
Burst Mode:
To handle scenarios where a specific handler has a large backlog of records (e.g., after a
prolonged outage), this scheduler supports a "Burst Mode".
- Trigger: When a
RetryHandlerdetects that it has processed a full page of records (indicating more data is likely available), it can request a burst execution. - Dedicated Resources: Burst requests are submitted to a separate, dedicated
ThreadPoolTaskExecutor(the "Burst Pool"). This ensures that high-load handlers can drain their backlogs quickly without consuming threads from the main "Fair Pool" and starving other handlers. - Mechanism: If the Burst Pool has capacity, the handler is scheduled to run again after a short delay (the "Burst Interval"). While bursting, the handler is marked as "running" so the main round-robin loop skips it, preventing double execution. If the Burst Pool is full, the request is ignored, and the handler falls back to the standard round-robin schedule.
-
Constructor Summary
ConstructorsConstructorDescriptionRoundRobinRetryScheduler(org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor workerPool, org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor burstPool, boolean enabled) -
Method Summary
Modifier and TypeMethodDescriptionvoidregisterHandler(RetryHandler handler, long initialDelaySeconds, long intervalSeconds) voidrequestBurst(RetryHandler handler, Duration burstInterval) voidsetApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher applicationEventPublisher) voidshutdown()voidunregisterHandler(RetryHandler handler)
-
Constructor Details
-
RoundRobinRetryScheduler
public RoundRobinRetryScheduler(org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor workerPool, org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor burstPool, boolean enabled)
-
-
Method Details
-
setApplicationEventPublisher
public void setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher applicationEventPublisher) - Specified by:
setApplicationEventPublisherin interfaceorg.springframework.context.ApplicationEventPublisherAware
-
registerHandler
-
unregisterHandler
-
requestBurst
-
shutdown
@PreDestroy public void shutdown()
-