2

I need to deliver some messages with high guarantee. This messages should be delivered as limited collections (100 at least as example). To resolve my task I think I should use spring batch. I need to configure exponentially increasing time for each next failed attempt. Each data object should have 5 delivery attempts as max. I expect to have a chance monitor all attempts and next retry time via db. Spring batch provides prepared tables for that. It seems my flow have only one job, but checking schema we can find that job only has status completion status (not payload): enter image description here

Also there are neither attempts count no next execution time.

Issues:

I'm not clear how to configure retry period strategy. Should I use different tool (like quartz) or I need dive deeper into spring batch? I do not want make my own solution for this task, it seems like ordinal and should have elegant solution.

Sergii
  • 7,044
  • 14
  • 58
  • 116

1 Answers1

2

Once you defined your job and how to execute it, you can use Spring Retry which provides an ExponentialBackOffPolicy out of the box. Here is an example:

import java.time.LocalDateTime;

import org.junit.Test;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

public class RetryTemplateTest {

    private Job job; // under test, has to be initialized

    @Test
    public void testExponentialBackoff() throws Exception {
        // configure backoff policy
        ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
        exponentialBackOffPolicy.setInitialInterval(1000);
        exponentialBackOffPolicy.setMultiplier(2.0);
        exponentialBackOffPolicy.setMaxInterval(10000);

        // configure retry policy
        SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(5);

        // configure retry template
        RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);
        retryTemplate.setRetryPolicy(simpleRetryPolicy);

        // run the job with retry on failure
        retryTemplate.execute(new RetryCallback<JobExecution, Exception>() {
            @Override
            public JobExecution doWithRetry(RetryContext context) throws Exception {
                return run(job);
            }
        });
    }

    private JobExecution run(Job job) throws Exception {
        System.out.println(LocalDateTime.now() + ": running job");
        if (true) { // just for test
            throw new Exception("Job failed");
        }
        return null;
    }
}

This example prints:

2019-03-13T09:19:21.882: running job
2019-03-13T09:19:22.892: running job
2019-03-13T09:19:24.893: running job
2019-03-13T09:19:28.894: running job
2019-03-13T09:19:36.895: running job

java.lang.Exception: Job failed

As you can see, the retry template has launched the job at seconds 21, 22, 24, 28 and 36 and retried the job at most 5 times before failing.

Hope this helps.

Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
  • thanks for your point. I thought about this, but I need control this mechanism. On other hand it's too expensive to keep in memory all non finished processes. In case of using `quartz` i'm not sure how if that's strategically nice (keep quartz job for spring job, or manage retry history for objects) I'd like to get recommendation or example. I vote your answer, but that's not solution I expected. – Sergii Mar 13 '19 at 15:57
  • How do i use Spring Retry if the jobs are executed asynchronous? – denfri.dev Apr 29 '20 at 14:58