NotificationServiceImpl implements NotificationService { @Override @Scheduled(cron = "${remind.cron}") public void sendRemindNotifications() { final NotificationType type = NotificationType.REMIND; List<Recipient> recipients = recipientService.findReadyToNotify(type); log.info("found {} recipients for remind notification", recipients.size()); recipients.forEach(recipient -> CompletableFuture.runAsync(() -> { try { emailService.send(type, recipient, null); recipientService.markNotified(type, recipient); } catch (Throwable t) { log.error("an error during remind notification for {}", recipient, t); } })); }  @Override @Scheduled(cron = "${backup.cron}") void sendBackupNotifications(); @Override @Scheduled(cron = "${remind.cron}") void sendRemindNotifications();  }
@Test public void shouldSendRemindNotificationsEvenWhenErrorsOccursForSomeRecipients() throws IOException, MessagingException, InterruptedException { final String attachment = "json"; Recipient withError = new Recipient(); withError.setAccountName("with-error"); Recipient withNoError = new Recipient(); withNoError.setAccountName("with-no-error"); when(recipientService.findReadyToNotify(NotificationType.REMIND)).thenReturn(ImmutableList.of(withNoError, withError)); doThrow(new RuntimeException()).when(emailService).send(NotificationType.REMIND, withError, null); notificationService.sendRemindNotifications(); verify(emailService, timeout(100)).send(NotificationType.REMIND, withNoError, null); verify(recipientService, timeout(100)).markNotified(NotificationType.REMIND, withNoError); verify(recipientService, never()).markNotified(NotificationType.REMIND, withError); }