[Rt-commit] rt branch, 4.2/shared-db-connections, created. rt-4.2.14-8-gaf28651

Alex Vandiver alexmv at bestpractical.com
Mon Nov 13 00:01:53 EST 2017


The branch, 4.2/shared-db-connections has been created
        at  af286514cd68b0485dc7611ba848269195cb1da1 (commit)

- Log -----------------------------------------------------------------
commit af286514cd68b0485dc7611ba848269195cb1da1
Author: Alex Vandiver <alex at chmrr.net>
Date:   Tue Nov 7 21:30:14 2017 -0500

    Add a critical error if DB connections are shared across the fork
    
    rt-server takes pains to close down the database connection before
    handing off control to the PSGI server, such that the database
    connection is not preserved across the `fork`.  DB connections which
    are so shared result in undefined behavior -- postgres, for instance,
    will reuse the same statement ids on the handle in different
    processes, resulting in errors of the form:
    
        DBD::Pg::st execute failed: ERROR:  prepared statement "dbdpg_p4068_1" already exists
    
    However, nothing prevents extensions from recreating the DB connection
    during their `to_app` methods -- RT::Extension::REST2-1.00 erroneously
    does so, for instance.
    
    While we could force-unset the connections, this would serve as a
    continuation of the mostly-silent error.  Instead, add an explicit
    error which causes server startup to fail, encouraging users to check
    for updated versions of plugins which will right the error.

diff --git a/lib/RT/PlackRunner.pm b/lib/RT/PlackRunner.pm
index 16eed5c..df52292 100644
--- a/lib/RT/PlackRunner.pm
+++ b/lib/RT/PlackRunner.pm
@@ -122,6 +122,20 @@ sub app {
         $app = Plack::Middleware::Test::StashWarnings->wrap($app);
     }
 
+    # Yell if we have reconnected to the database -- if we have, it
+    # will be shared across all children processes.
+    if ($RT::Handle and $RT::Handle->dbh) {
+        $RT::Logger->critical(<<EOT);
+
+An extension has reconnected to the database too late into
+initialization.  This will cause the connection to be shared across
+processes, which will result in undefined behavior.  Plugins must
+perform database-requiring initialization in `init`, not `to_app`;
+check for upgraded versions of your plugins which resolve this.
+
+EOT
+    }
+
     return $app;
 }
 
diff --git a/sbin/rt-server.in b/sbin/rt-server.in
index 5b9fecd..e82e43a 100644
--- a/sbin/rt-server.in
+++ b/sbin/rt-server.in
@@ -132,7 +132,7 @@ EOF
     }
 }
 
-# we must disconnect DB before fork
+# Disconnect from the database, having done all of the setup.
 if ($RT::Handle) {
     $RT::Handle->dbh->disconnect if $RT::Handle->dbh;
     $RT::Handle->dbh(undef);

-----------------------------------------------------------------------


More information about the rt-commit mailing list