2

I have a nginx loadbalancer in front of two tomcat instances each contains a spring boot application. Each spring boot application executes a batch that writes data in a database. The batch executes every day at 1am. The problem is that both instances execute the batch simultaniously which i don't want.

Is there a way to keep the batchs deployed in two instances and tell tomcat or nginx to start the batch in master server (and the slave server doesn't run the batch).

If one of the servers stops, the second server could start the batch on his behalf.

Is there a tool in nginx or tomcat (or some other technology) to do that ?

thank you in advance.

Compo
  • 36,585
  • 5
  • 27
  • 39
batmaniac
  • 392
  • 4
  • 22
  • Jobs are either scheduled to run at a specific time or triggered by an external system. Here, you have jobs that are scheduled at 1am and you are looking for a way to trigger them through tomcat or nginx on one instance and not the other. This is not clear. Can you elaborate on how your jobs are scheduled? – Mahmoud Ben Hassine Feb 14 '20 at 09:52
  • it's a spring scheduler (with @EnableScheduling annotation). – batmaniac Feb 19 '20 at 20:52

3 Answers3

3

Here is a simplistic design approach.

Since you have two scheduled methods in the 2 VMs triggered at same time, add a random delay to both. This answer has many options on how to delay the trigger for a random duration. Spring @Scheduled annotation random delay

Inside the method run the job only if it is NOT already started (by the other VM). This could be done with a new table to track this.

Here is the pseudo code for this design:

@Scheduled(cron = "schedule expression")
public void batchUpdateMethod() {
     //Check database for signs of job running now.
     if (job is not running){
         //update database table to indicate job is running
         //Run the batch job
         //update database table to indicate job is finished
     }
}

The database, or some common file location, should be used as a lock to sync between the two runs, since the two VMs are independent of each other.

For a more robust design, consider Spring Batch Spring Batch uses a database for its jobs (JobsRepository). By default an in memory datasource is used to keep track of running jobs and their status. In your setup, the 2 instances are (most likely) using their own in memory database. Multiple instances of Spring Batch can coordinate with each other as a cluster and one can run jobs, while the other actasa backup, if the jobsRepository database is shared. For this you need to configure the 2 instances to use a common datasource.

Here are some docs: https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#jobrepository

https://docs.spring.io/spring-batch/docs/current/reference/html/job.html#configuringJobRepository

Shankar
  • 2,625
  • 3
  • 25
  • 49
  • i don't use spring batch with all the tables stuff. Just the scheduler part so i don't have all those spring batch tables. I don't use jobs and i don't want to (unless it's mandatory for my use case) – batmaniac Feb 19 '20 at 20:55
  • @batmaniac I wrongly assumed you were already using Spring Batch. I will update my answer. – Shankar Feb 21 '20 at 19:18
3

If you design two app server instances to run the same job at the same time, then by design, one will succeed to create a job instance and the other will fail (and this failure can be ignored). See Javadoc of JobRepository. This is one of the roles of the job repository: to act as a safeguard against duplicate job executions in a clustered environment.

If one of the servers stops, the second server could start the batch on his behalf. Is there a tool in nginx or tomcat (or some other technology) to do that ?

I believe there is no need for such tool or technology. If one of the servers is down at the time of the schedule, the other will be able to take things over and succeed in launching the job.

Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
0

I did implement a simple BCM Server functionality, where all servers do register(create a Server-table entry) with their unique IP. The Servers need to register within a defined time(e.g. 10 sec). If a Server does not register within time(last update timestamp > 10 sec), then the Server gets de-registered(delete Server-table entry) by the Server, which do register.

At the end I do have a table with ordered Server entries and can define the task uniquely to the registered Servers.

The Implementation is very simple and Works perfectly. Before I did also have in mind the Spring Batch Job Sharing functionality, but I wanted zu have a more lightweight and more flexible Solution.

Currently I use it in all my projects where I need to have Batch-Processing implemented.

Martin
  • 1
  • 1