如何解决Spring重试for循环
我的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次,然后如果重试已用尽,请继续操作,并在for循环中为下一个用户发送电子邮件。
真正的行为:如果发生错误,服务将捕获异常并停止循环。
如果我将重试逻辑移至此方法:
@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 ...");
});
如果回调正常退出,则故障将“恢复”,并且异常不会重新引发。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。