How to run clustered camel-quartz schedulers in spring-boot

Viewed 298

Our component has multiple camel-quartz schedulers. When we deploy multiple instances of our application on different servers, these scheduler runs in all the instances and execute the logic. We want that only one of those instances should run the scheduler.

To achieve this, we are thought of using clustered scheduling mode of Quartz. For that I read that we need to put relevant properties in quartz.properties file with isClustered=true. Point to note here is we are using Apache Ignite as our persistent store. So I also put ignite jdbc thin driver as our datasource. The properties file is placed in src/main/resources folder and our camel routeBuilder is as below:

public void configure() throws Exception
    {
        AbstractApplicationConfiguration.RouteConfig routeConfig = appConfig.getCamel().fetchRoute(ROUTE_ID);
        from(routeConfig.getInputEndpoints()[0])
            .to(appConfig.getCamel().getMetricEndpoints().getTimerEndpoint() + "&" + CAMEL_MICROMETER_ACTION_START + "&" + CAMEL_MICROMETER_TAG_ROUTE + ROUTE_ID)
            .to(appConfig.getCamel().getMetricEndpoints().getCounterEndpoint() + "&" + CAMEL_MICROMETER_ACTION_START + "&" + CAMEL_MICROMETER_TAG_ROUTE + ROUTE_ID)
    }

According to the resource used as reference to achieve this: https://developers.redhat.com/blog/2017/08/10/using-clustered-camel-quartz-jobs-on-jboss-eap the quartz.properties should be set by default, but when we run our application in two different instances, the scheduler is still running in both the instances.

After running this application in debug mode also I am not able to see that Camel is able to read this properties file. When I run multiple schedulers on my machine all of them execute. So clustering is not happening anyways.

Kindly help on how do we set the quartz.properties file to the propertiesFile of camel-quartz component configuration?

2 Answers

Camel has now some built-in clustering capabilities - see here.

In your particular case, you could model a route which is taking the leadership when starting the quartz scheduler, preventing thereby other nodes from firing.

Set it up is very easy and all you need is to prefix singleton endpoints according to the master component syntax: master:namespace:delegateUri

This would result in something like this:

from("master:my-cluster:quartz://myGroup/myTimerName?cron=0+0/5+12-18+?+*+MON-FRI")
        .routeId("clustered")
        .log("Clustered quartz scheduler !");  

Quartz needs a JDBC job store in case you have multiple servers running in a cluster. Also, it's important that each server is assigned a unique instance-id. See https://medium.com/javarevisited/spring-boot-using-quartz-in-mode-cluster-e1d71e4af4b9 for a complete example, including docker-compose files.

Here are the most important settings to use:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/myapp
    username: xxx
    password: xxx
  quartz:
    job-store-type: jdbc
    jdbc:
      initialize-schema: never
    properties:
      org:
        quartz:
          scheduler:
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            isClustered: true

Related