#1933 ✓resolved
Tobin Stelling

play-1.3.0 leaks database connections when configured for multiple databases

Reported by Tobin Stelling | April 6th, 2015 @ 12:47 PM | in 1.3.1 (closed)

Framework version: 1.3.0
Platform you're using: linux, java-1.7.0_75, postgresql 9.2

We recently upgraded our apps to play-1.3.0 and noticed a few instances where Play leaks database connections. You can observe the leak with C3P0's management bean numBusyConnections. The count can increment to your maxPool size. Once it has reached maxPool size, Play will return 500 error pages (because c3p0 will time out waiting to checkout a connection).

public class Application extends Controller {
    public static void index() {
        JPA.closeTx(JPA.DEFAULT);
        renderText("Connection leaked!");
    }
}
Open jvisualvm and look at the numBusyConnections mbean for your "other_database" connection pool. Invoke Application.index() a few times. Notice how each time you invoke it, your numBusyConnections increments by one and never goes back down.

Let's walk through what happens when JPA.closeTx(JPA.DEFAULT) is called. The transaction is open, so it proceeds and retrieves the correct EntityManager from our JPA.currentEntityManager threadlocal. But then it calls DB.getConnection() instead of DB.getConnection(name). Because we are working on JPA.DEFAULT, this is fine (DB.getConnection() calls DB.getConnection(JPA.DEFAULT)). However, it could be problematic if we call JPA.closeTx("other_database"). However this is not the exact source of the leak. Next, the method tests if the transaction for our EntityManager is active and behaves appropriately. The problem is in the finally{} block: it calls JPA.clearContext(). JPA.clearContext() nukes your JPA.currentEntityManager threadlocal completely. In this case this is not what we want to have happen. We have finished the transaction for our JPA.DEFAULT EntityManager and closed the EntityManager itself, but we have not done this for our "other_database" EntityManager which is still open and still has an active transaction. Because we nuke all entries from JPA.currentEntityManager, our EntityManager for "other_database" goes into limbo and is never closed. As far as I can tell its transaction remains forever open. Furthermore, we probably do not want to close out the EntityManager for "other_database," because we called JPA.closeTx(JPA.DEFAULT), not JPA.closeTx("other_database").

JPA.startTx() has a similar problem: it calls createContext(), which subsequently calls clearContext().

The next issue is with Jobs. Again, assume we have two databases, JPA.DEFAULT and "other_database." Invoking Application.index() for this controller leaks a connection:

public class Application extends Controller {
    public static void index() {
        SomeJob job = new SomeJob();
        Promise p = job.now();
        await(p);
        renderText("Connection leaked!");
    }

    @NoTransaction
    public static class SomeJob extends Job {

        @Override
        public void doJob() throws Exception {
            Thread.sleep(10000);
            Logger.info("Job is done");
        }
    }
}

This leaks a connection because JPAPlugin.afterInvocation() calls JPAPlugin.closeTx(). JPAPlugin.closeTx() is a deprecated method that closes only the JPA.DEFAULT EntityManager. Instead, JPAPlugin.afterInvocation() should loop through all keys in JPA.currentEntityManager and call JPA.closeTx() on each key. JPAPlugin.afterInvocation is called after the await(p) because of javaflow Continuation magic.

Comments and changes to this ticket

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2>Play framework</h2>

Play makes it easier to build Web applications with Java. It is a clean alternative to bloated Enterprise Java stacks. It focuses on developer productivity and targets RESTful architectures. Learn more on the <a href="http://www.playframework.org">http://www.playframework.org</a> website.<br><br>

<h2>Source code is hosted on github</h2>Check out our repository at <a href="http://github.com/playframework/play">http://github.com/playframework/play</a><br><br>

<h2>Contributing, creating a patch</h2> Please read the <a href="http://play.lighthouseapp.com/projects/57987/contributor-guide">contributor guide</a><br><br>

<h2>Reporting Security Vulnerabilities</h2> Since all bug reports are public, please report any security vulnerability directly to <em>guillaume dot bort at gmail dot com</em>.<br><br>

<h2>Creating a bug report</h2> Bug reports are incredibly helpful, so take time to report bugs and request features in our ticket tracker. We’re always grateful for patches to Play’s code. Indeed, bug reports with attached patches will get fixed far quickly than those without any.<br><br>

Please include as much relevant information as possible including the exact framework version you're using and a code snippet that reproduces the problem.<br><br>

Don't have too much expectations. Unless the bug is really a serious "everything is broken" thing, you're creating a ticket to start a discussion. Having a patch (or a branch on Github we can pull from) is better, but then again we'll only pull high quality branches that make sense to be in the core of Play.

Tags

Pages