使用for循环进行Spring重试



我的RetryTemplate配置:

@Configuration
@EnableRetry
public class RetryTemplateConfig {
@Value("${spring.retry.attempts}")
private int maxAttempts;
@Value("${spring.retry.period}")
private long backOffPeriod;
@Bean
public RetryTemplate retryTemplate() {
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(maxAttempts);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(backOffPeriod);
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
}

调用使用Retry:的方法的调度方法

@Scheduled(cron = "${schedule.cron.update.users}")
public void sendToUsers() throws Exception {
log.info("Scheduled sending for users started");
try {
mailSender.sendToUsers();
} catch (MessagingException | IOException | TemplateException e) {
log.error("Error occurred while sending email message to users: {}", e.toString());
}
log.info("Scheduled sending for users finished");
}

我想使用RetryTemplate:的方法

public void sendToUsers() throws Exception {
String subject = reportGenerationService.getEmailSubjectForUser();
Map<String, List<BadUtmMark>> utmMarksGroupedByEmail = userService.getUtmMarksGroupedByEmail(LocalDate.now());
if (utmMarksGroupedByEmail.isEmpty()) {
log.info("All's fine - no broken utm marks in database. Emails to users will not be send.");
}
for (Map.Entry<String, List<BadUtmMark>> pair : utmMarksGroupedByEmail.entrySet()) {
retryTemplate.execute(retryContext -> {
String emailTo = pair.getKey();
List<BadUtmMark> badUtmMarks = pair.getValue();
String report = reportGenerationService.getReportForUser(emailTo, badUtmMarks, template);
MimeMessage mimeMessage = getMimeMessage(subject, report, Collections.singletonList(emailTo));
log.info("Message will be sent to: {}; from: {}; with subject: {}", pair.getKey(), from, subject);
mailSender.send(mimeMessage);
return true;
});
}
}

预期行为:我想为5个人发送电子邮件。如果出现错误,请尝试再向该用户发送5次电子邮件,然后,如果重试次数用完,请继续发送电子邮件给循环中的下一个用户。

实际行为:如果发生错误,服务将捕获异常并停止循环。

如果我将重试逻辑移到此方法:

@Scheduled(cron = "${schedule.cron.update.users}")
public void sendToUsers() throws Exception {
log.info("Scheduled sending for users started");
try {
retryTemplate.execute(retryContext - > {
log.warn("Sending email to users. Attempt: {}", retryContext.getRetryCount());
mailSender.sendToUsers();
return true;
});
} catch (MessagingException | IOException | TemplateException e) {
log.error("Error occurred while sending email message to users: {}", e.toString());
}
log.info("Scheduled sending for users finished");
}

它效果更好,但仍然不是我所期望的。在这种情况下,如果出现错误,服务将尝试再发送5次电子邮件,但如果重试次数用完,服务将停止循环。因此,如果其中一个用户出现错误,服务将尝试为该用户再发送5次,然后将停止,忽略地图中的其他用户。

但我想对地图中的每封电子邮件重试5次我该怎么做?

在您的第一个版本中,请使用此execute。。。

/**
* Keep executing the callback until it either succeeds or the policy dictates that we
* stop, in which case the recovery callback will be executed.
*
* @see RetryOperations#execute(RetryCallback, RecoveryCallback)
* @param retryCallback the {@link RetryCallback}
* @param recoveryCallback the {@link RecoveryCallback}
* @throws TerminatedRetryException if the retry has been manually terminated by a
* listener.
*/
@Override
public final <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback,
RecoveryCallback<T> recoveryCallback) throws E {
return doExecute(retryCallback, recoveryCallback, null);
}
template.execute(context -> {
...
}, context -> {
logger.error("Failed to send to ...");
});

如果回调正常退出,则失败为"0";回收的";并且不重新引发异常。

最新更新