2

I have the following code in which I must gather some data and based on certain logic, send emails.

@Transactional
public void sendReports() {
    List<Execution> finishedExecutions = executionService.findAllFinishedExecutionsWithPendingReport();
    for (Execution execution : finishedExecutions) {
        if (!execution.anyBatchFailed()) {
            execution.setReportSent(true);
            continue;
        }

        Store store = execution.getStore();
        TypeConsistency typeConsistency = execution.getTypeConsistency();
        Set<StoreRecipient> recipients = storeRecipientRepository.findAllByStoreAndTypeConsistency(store, typeConsistency);

        try {
            LocalDateTime executionCreatedAt = execution.getCreatedAt().toLocalDateTime();
            mailingService.sendMessageWithAttachment(
                    EmailWithAttachment.csv()
                            .to(recipients.stream().map(r -> r.getRecipient().getEmail()).collect(Collectors.toSet()))
                            .filename("foo")
                            .subject("bar")
                            .contents("My CSV Example")
                            .build()
            );
            execution.setReportSent(true);
        } catch (IOException e) {
            alertService.sendAlert("foo", "bar");
        }
    }
}

So far the code works, however, due to the nature of email sending, the transaction started by @Transactional could potentially be left open for more than I'd like (30+ seconds if we have to send many emails). This goes against what I've read about transactions and how they should be relatively short lived.

The real reason why I'm forced to use @Transactional here is because the Store in Execution and other attributes of most of the entities you see here use lazy loading. If I don't use transactions, Hibernate throws a LazyInitializationException. So, in short, I'm forced to use transactions here in the same method that sends emails just for the sake of lazy loading things.

Is there a way to prevent this without having to resort to anti-patterns such as enable_lazy_load_no_trans and FetchType.EAGER?

Morgan
  • 907
  • 1
  • 13
  • 35
  • You can [tell Hibernate to explicitly initialize the lazy-loaded collections that you need](https://stackoverflow.com/a/19928738/4216641) (warning: this will result in `` many queries per collection loaded). – Turing85 Aug 21 '21 at 13:17
  • You may use an async queue which processes the email requests. Obviously, all related mail information should be passed to the queue via a detached object... – Kemal Kaplan Aug 21 '21 at 14:16
  • @KemalKaplan By async queue you mean an `@Async` method called from this one with a detached object as a parameter? – Morgan Aug 21 '21 at 15:00

0 Answers0