bbottema/simple-java-mail

Problem with stopping tomcat8 after mail send

Tsyklop opened this issue · 7 comments

I get this error in log after send mail:

10-May-2017 20:49:25.317 INFO [main] org.apache.catalina.core.StandardServer.await A valid shutdown command was received via the shutdown port. Stopping the Server instance.
10-May-2017 20:49:25.318 INFO [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
10-May-2017 20:49:25.371 INFO [main] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-61348"]
10-May-2017 20:49:25.425 INFO [main] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
10-May-2017 20:49:25.466 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ROOT] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
10-May-2017 20:49:25.468 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
 com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)
10-May-2017 20:49:25.468 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-1-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.469 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-2-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.470 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-3-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.471 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-4-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.475 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-5-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.476 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [pool-6-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
 java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 java.lang.Thread.run(Thread.java:745)
10-May-2017 20:49:25.492 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
10-May-2017 20:49:25.497 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-nio-61348"]
10-May-2017 20:49:25.498 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]
10-May-2017 20:49:25.499 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-nio-61348"]

To stop tomcat8 I need to call the stop command twice. I use async sending.

I'm sorry, but how is this related to Simple Java Mail? I don't see any references to it. Also, why do you have 6 connection pools?

@bbottema This happens only after I send an email. If you do not send, then there will be no such error.

This happens right after sending the email? Or when you close Tomcat after sending the email? If you try to close the server while the email is still being processed in async mode, then there's ofcourse still a thread running. Might that be the case?

If you share the code in a minimal version, I can try to reproduce it and analyse it, but as it is I don't have much to go on. Also include Tomcat version and Java version.

@bbottema The message is sent and after a while I stop tomcat 8 and get this error.

I use: Tomcat 8.5.8, Java 8.

Email class:

import org.apache.commons.io.Charsets;
import org.simplejavamail.email.Email;
import org.simplejavamail.email.Recipient;
import org.simplejavamail.mailer.Mailer;
import org.simplejavamail.mailer.config.ServerConfig;
import org.simplejavamail.mailer.config.TransportStrategy;
import org.simplejavamail.util.ConfigLoader;

import javax.mail.Message.RecipientType;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

public class EmailFactory extends Email {

    private String ROOT;
    private String SEPARATOR = File.separator;

    private Email EMAIL;
    private String ADMIN_NAME = "Admin";
    private String ADMIN_EMAIL = "email@gmail.com";
    private String ADMIN_PASSWORD = "password";

    private int TYPE_REGISTER = 1;
    private int TYPE_FORGOT = 2;

    public EmailFactory(String ROOT) {
        this.ROOT = ROOT;
        this.EMAIL = new Email();
        /*ConfigLoader.loadProperties("simplejavamail.properties", false);
        ConfigLoader.loadProperties("overrides.properties", false);*/
    }

    public void Send(String to, int type, boolean isurl, String url, boolean issubmgs, boolean async) throws IOException {
        String tpl = getTemplate();
        if (!tpl.isEmpty()) {
            EMAIL.setFromAddress(ADMIN_NAME, ADMIN_EMAIL);
            EMAIL.addRecipient("", to, RecipientType.TO);
            if(type == TYPE_REGISTER) {
                EMAIL.setSubject("test");
                tpl = tpl.replaceAll("%mgs%", "test");
                tpl = RegisterTpl(tpl, isurl, url, issubmgs);
            } else if(type==TYPE_FORGOT) {
                EMAIL.setSubject("test");
            }
            //System.out.println(tpl);
            EMAIL.setTextHTML(tpl);
            new Mailer(new ServerConfig("smtp.gmail.com", 465, ADMIN_EMAIL, ADMIN_PASSWORD), TransportStrategy.SMTP_SSL).sendMail(EMAIL, async);
        }
    }

    private String getTemplate() throws IOException {
        File tpl = new File(ROOT+SEPARATOR+"template"+SEPARATOR+"mail"+SEPARATOR+"mail.html");
        if(tpl.exists()) {
            byte[] encoded = Files.readAllBytes(Paths.get(tpl.toURI()));
            return new String(encoded, StandardCharsets.UTF_8);
        } else {
            return "";
        }
    }
}

Send:

EMAIL.Send("myemail@gmail.com", 1, true, "http://localhost:8080/", true, true);

I think I know what the problem is. The connection pool that is started because of the async mode is never shut down, because Simple Java Mail cannot know when you are done sending emails.

However, I'm making a change because of which the connection pool is shut down as soon as all known emails have been sent. If new emails are requested lateron, a new connection pool will be spinned up to once again send more emails. And so on.

This way Simple Java Mail should never keep processes running anymore when sending of email is finished.

I've release 4.2.2. Can you please try again? It might take some time to appear in maven central though (OSS Sonatype needs to sync to it first).

Oh. it works. Thanks.