Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sending email from ForkJoinPool.commonPool() (CompletableFuture) thread causes error #30479

Closed
turboezh opened this issue May 11, 2023 · 9 comments
Labels
status: invalid An issue that we don't feel is valid

Comments

@turboezh
Copy link

I've met an error trying to send an email from ForkJoinPool common pool (CompletableFuture.runAsync(), ForkJoinPool.commonPool().execute(), ...).

The error I can reproduce is Provider for jakarta.activation.spi.MailcapRegistryProvider cannot be found but I also met a Not provider of jakarta.mail.util.StreamProvider was found.

  • It emerges only from packaged jar (including container env built with bootBuildImage). Running an app directly from IDE cause no error.
  • Changing JDK had no effect (tested with Temurin 17 JDK, Liberica 17 JDK and JRE).
  • Sending email from Kotlin coroutine thread pool cause no error.
  • Sending email from newly created pool cause no error (tested with Executors.newFixedThreadPool(8)).

I've made reference project freshly created by Spring initializr: https://github.com/turboezh/mail-test.
Spring Boot version is 3.0.6.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label May 11, 2023
@scottfrederick
Copy link
Contributor

scottfrederick commented May 11, 2023

Thanks for the report and the sample. I've been able to reproduce the Not provider of jakarta.mail.util.StreamProvider was found error.

This is the full stack trace when the error occurs:

java.lang.IllegalStateException: Not provider of jakarta.mail.util.StreamProvider was found
	at jakarta.mail.util.FactoryFinder.find(FactoryFinder.java:64)
	at jakarta.mail.util.StreamProvider.provider(StreamProvider.java:177)
	at jakarta.mail.Session.<init>(Session.java:254)
	at jakarta.mail.Session.getInstance(Session.java:323)
	at org.springframework.mail.javamail.JavaMailSenderImpl.getSession(JavaMailSenderImpl.java:163)
	at org.springframework.mail.javamail.JavaMailSenderImpl.createMimeMessage(JavaMailSenderImpl.java:341)
	at abc.email.test.EmailSender.sendSimple(EmailSender.java:33)
	at abc.email.test.EmailSender.lambda$test$0(EmailSender.java:59)
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804)
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

Spring Boot auto-configures a org.springframework.mail.javamail.JavaMailSenderImpl, but Boot is not in the code path when messages are sent as JavaMailSenderImpl is part of Spring Framework. Since jakarta.mail APIs are involved, the root cause may be out of the Spring Framework team's control also, but we'll need to transfer the issue so the Framework team can take a look.

I thought this might be a case of thread safety when the CompletableFuture invocation and the After async invocation run at the same time, but that does not appear to be the case. If the Before async and After async invocations are removed from the sample and a Thread.sleep(10000) is added after the CompletableFuture.runAsync returns, the error still happens.

@bclozel bclozel transferred this issue from spring-projects/spring-boot May 12, 2023
@ztomic
Copy link

ztomic commented May 12, 2023

It could be problem with class loader of ForkJoinPool, something like in spring-projects/spring-boot#19427

@turboezh
Copy link
Author

turboezh commented May 13, 2023

It could be problem with class loader of ForkJoinPool

Yes, it seems it is the case.

Adding

Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());

before mail sending leads to Not provider of jakarta.mail.util.StreamProvider was found.

P.S.: Now I see tons of Classloader issue with CompletableFuture problems. It seems this makes the default CompletableFuture pool a bit useless. 🥲

@turboezh
Copy link
Author

Another news: I don't know why, but after changing dependency to com.sun.mail:jakarta.mail:2.0.1 it all works fine without errors.
org.eclipse.angus:jakarta.mail:2.0.1 and 1.0.0 fails.

@evaldasu
Copy link

Another news: I don't know why, but after changing dependency to com.sun.mail:jakarta.mail:2.0.1 it all works fine without errors. org.eclipse.angus:jakarta.mail:2.0.1 and 1.0.0 fails.

It is because com.sun.mail:jakarta.mail:2.0.1 doesn't have this.streamProvider = StreamProvider.provider(); in it's private Session constructor as opposed to org.eclipse.angus:jakarta.mail.

And the error Not provider of jakarta.mail.util.StreamProvider was found comes from StreamProvider.provider()

@dipsk2
Copy link

dipsk2 commented Sep 11, 2023

Is there a fix or a workaround that someone found for this issue? We are facing the same.

@turboezh
Copy link
Author

@dipsk2, this one works for me:

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-mail") {
        exclude("org.eclipse.angus", "jakarta.mail")
        implementation("com.sun.mail:jakarta.mail:2.0.1")
    }
}

I think a latest version will work too.

@bclozel
Copy link
Member

bclozel commented Dec 1, 2023

Closing this issue as this is indeed independent of Spring Framework as explained in this comment.

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Dec 1, 2023
@bclozel bclozel added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 1, 2023
@jmehrens
Copy link

JakartaMail PR 701 should fix this issue:

jakartaee/mail-api#701

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

8 participants