Issue
I need to have two schedulers that each run at different fixed intervals. I also need the ability to stop and start the quoteScheduler
based on whether or not the US stock market is open.
The quoteScheduler
needs to run once per minute if the US stock market is open. But, I only need to check if the US stock market is open less frequently (say every 10 minutes). How can I set it up so that my marketDataScheduler
runs every 10 minutes and can start and stop my quoteScheduler
which will run every 1 minute only when the marketDataScheduler
tells it to start.
Right now, the code below only follows the schedule configured by MarketDataSchedulerConfiguration
and I am having trouble figuring out how to set up the two different schedules.
@Configuration
@EnableScheduling
public class QuoteSchedulerConfiguration {
@Scheduled(fixedRate = 60000)
public void scheduleByFixedRate() {
}
}
@Service
public class QuoteServiceScheduler {
private final ScheduledAnnotationBeanPostProcessor postProcessor;
private final QuoteSchedulerConfiguration schedulerConfiguration;
private final QuoteService quoteService;
public QuoteServiceScheduler(QuoteService quoteService,
ScheduledAnnotationBeanPostProcessor postProcessor,
QuoteSchedulerConfiguration schedulerConfiguration) {
this.postProcessor = postProcessor;
this.schedulerConfiguration = schedulerConfiguration;
this.quoteService = quoteService;
}
public void startSchedule() {
postProcessor.postProcessAfterInitialization(schedulerConfiguration, "");
quoteService.getLatestPrices();
}
public void stopSchedule() {
postProcessor.postProcessBeforeDestruction(schedulerConfiguration, "");
}
@Configuration
@EnableScheduling
public class MarketDataSchedulerConfiguration {
private final MarketDataScheduler marketDataScheduler;
public MarketDataSchedulerConfiguration(MarketDataScheduler marketDataScheduler) {
this.marketDataScheduler = marketDataScheduler;
}
@Scheduled(fixedRate = 60 * 1000 * 10)
public void scheduleByFixedRate() {
marketDataScheduler.startSchedule();
}
}
@Service
public class MarketDataScheduler {
private final MarketDataServiceImpl marketDataServiceImpl;
private final QuoteServiceScheduler quoteServiceScheduler;
public MarketDataScheduler(MarketDataServiceImpl marketDataServiceImpl,
QuoteServiceScheduler quoteServiceScheduler) {
this.marketDataServiceImpl = marketDataServiceImpl;
this.quoteServiceScheduler = quoteServiceScheduler;
}
public void startSchedule() {
if (isUSMarketOpen()) {
quoteServiceScheduler.startSchedule();
} else {
quoteServiceScheduler.stopSchedule();
}
}
Solution
I discovered a simpler approach using cron
to set the schedule instead of fixedRate
. cron
gives more precise control over when to run the job and can be set up to start the minute-by-minute update only when the US stock market is open. For example, below I am starting the job at 4:00 am eastern time to capture pre-market trading activity. Simply add this to a MarketDataScheduler
and remove all the other classes that were attempting to simulate the precision provided by cron
.
@Scheduled(cron = "0 */1 4-16 * * MON-FRI", zone = "America/New_York")
public void startSchedule() {
boolean isMarketOpen = isUSMarketOpen();
if (isMarketOpen) {
quoteService.getLatestPrices();
} else {
LOGGER.info().log("US stock market is closed. Potential holiday - Closed during normal trading hours");
}
}
Answered By - Michael