9

I am trying to make my Service Method retrying on failure with Springs @Retryable.

@Retryable(backoff = @Backoff(delay = 1000), maxAttempts = 3)
@Transactional(rollbackFor = Throwable.class)
public Something saveSomething(Something something) {
  //some logic and saving
}

The Problem is, that the exception appears after saving the something-object. So the Transaction is rolled back and the Method is called again. The Difference is that the id of the something-object is not null anymore but the value it got from the previous saving process by Hibernate so in the second attempt Hibernate does not save the object but tries to update it. Since no entry is in the DB the update doesn't do anything and the object is not persited to the DB.

After recognizing this i tried to set the stateful property of @Retryable to true:

@Retryable(backoff = @Backoff(delay = 1000), maxAttempts = 3, stateful = true)
@Transactional(rollbackFor = Throwable.class)
public Something saveSomething(Something something) {
  //some logic and saving
}

But with that config saveSomething() is just called once and der is no second attempt.

Has anyone suggestions to solve this problem?

1 Answers1

7

When you use stateful retry; the caller has to call the method again for the next retry; the state maintains how many attempts have been made. So, you have to use try/catch and call saveSomething in a loop (with a new Something, or setting the id to null) until it succeeds - using an @Recover method for when retries are exhausted, where you can throw a different exception so the caller knows the difference between something that should be retried and when retries are exhausted.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks for your answer! I thought there would maybe be a more spring like solution than that. So just for the understanding. The only advantage of the @Retryable-annotation with stateful set to true, is counting the number of attempts and than calling the recover()-method? – Philipp Schweiger Feb 06 '19 at 19:37
  • Stateful retry is generally used by a message-driven source - e.g. RabbitMQ, JMS, where the message is rejected all the way back to the broker and redelivered for each retry. In this case, aside from the built-in back off policies to suspend the thread and keeping track of the count, yes, support the recover method is a reason to use it. – Gary Russell Feb 06 '19 at 19:50
  • @GaryRussell thanks Gary, but I couldn't figure out what kind of loop should we use? do we need to handle delay, backoff, etc. by ourselves? is there any sample for that? – Samet Baskıcı Jul 26 '21 at 17:14
  • Sorry about my previous comment I thought the question was about spring-kafka. No; the retry template will take care of the backOff; just call the method immediately; the template will sleep for the next backOff before calling the advised method. – Gary Russell Jul 26 '21 at 17:38