Play Framework:数据库连接池关闭

时间:2017-05-06 19:59:49

标签: java playframework-2.0 sbt hikaricp

我使用HikariCP jdbc连接池运行Play应用程序。

应用程序将运行一段时间,但在很短的时间后它将关闭连接池,这意味着我无法再使用该应用程序。

SBT build:

name := "virtual-betting"
version := "1.0"

lazy val root = (project in file(".")).enablePlugins(PlayJava).settings(javacOptions ++= Seq("-source", "1.8", "-target", "1.8"))

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  javaJdbc,
  javaJpa,
  javaJpa.exclude("org.hibernate.javax.persistence", "hibernate-jpa-2.1-api"),
  "org.hibernate" % "hibernate-core" % "5.1.0.Final",
  "org.hibernate" % "hibernate-entitymanager" % "5.1.0.Final",
  "com.typesafe.play" % "play-java-jpa_2.11" % "2.5.3",
  "org.springframework" % "spring-context" % "4.2.4.RELEASE",
  "org.webjars" % "bootstrap" % "3.3.4",
  "mysql" % "mysql-connector-java" % "5.1.42",
  cache,
  javaWs,
  "org.jsoup" % "jsoup" % "1.7.2",
  "org.apache.commons" % "commons-email" % "1.4",
  "org.apache.cxf" % "cxf-rt-rs-client" % "3.1.6",
  "com.google.code.gson" % "gson" % "2.7",
  "com.squareup.okhttp3" % "okhttp" % "3.4.1"
)

fork in run := false


fork in run := true

application.conf:

## Database Connection Pool
# https://www.playframework.com/documentation/latest/SettingsJDBC
# ~~~~~
# Play doesn't require a JDBC database to run, but you can easily enable one.
#
# libraryDependencies += jdbc
#

play.db {
  # The combination of these two settings results in "db.default" as the
  # default JDBC pool:
  config = "db"
  default = "default"

  pool = "hikaricp"
  # Play uses HikariCP as the default connection pool.  You can override
  # settings by changing the prototype:

  prototype {
    pool = "hikaricp"

    # Sets a fixed JDBC connection pool size of 50
    hikaricp.minimumIdle = 0
    hikaricp.maximumPoolSize = 30
    hikaricp.connectionTimeout = 30000
    hikaricp.idleTimeout = 600000
    hikaricp.maxLifetime = 1800000
    hikaricp.leakDetectionThreshold = 5000
    hikaricp.connectionTestQuery = "SELECT 1"
    hikaricp.readOnly = false

    hikari.dataSourceClassName = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
    # The database url
    #url = "jdbc:mysql://localhost:3306/madduxsp_sportsbook?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"

    registerMBeans = true
    poolName = "sportsbook_pool"
  }
}

db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost:3306/madduxsp_sportsbook_new?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"
db.default.username=root
db.default.password=mypassword
db.default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit

application.secret="mysecret"

spring.context.location=application-context.xml

我已经编写了一些代码来保持数据库连接处于活动状态,以防万一由于不活动而关闭。

我的DbKeepAliveService:

package services;

import play.Logger;
import play.db.jpa.JPAApi;
import util.DbKeepAliveTask;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Timer;

@Singleton
public class DbKeepAliveService {

    private final JPAApi jpa;

    @Inject
    public DbKeepAliveService(JPAApi jpa) {
        this.jpa = jpa;

        DbKeepAliveTask dbKeepAliveTask = new DbKeepAliveTask(jpa);
        Logger.info("Application has started");

        Timer timer = new Timer("dbKeepAlive", true);
        timer.schedule(dbKeepAliveTask, 0, 1200000);
    }
}

除非这不起作用。这是我的日志:

2017-05-06 06:12:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:32:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:52:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:58:35,894 [INFO] from application in Thread-8 - Application shutdown...
2017-05-06 06:58:36,054 [INFO] from application in Thread-8 - Shutting down connection pool.

有没有人知道为什么它可能会继续关闭Db连接池?我怀疑这与我的配置有关,但我老实说无法确定。

我还看到它可能与未在生产模式下运行应用程序有关,但我确定了秘密。

我使用以下命令运行应用程序:

./bin/virtual-betting -Dconfig.file=conf/production.conf -Dplay.crypto.secret="mysecret" &

play.crypto.secret文件中设置conf/production.conf属性。

长期以来一直在关注这一点,所以非常感谢你的帮助!

3 个答案:

答案 0 :(得分:5)

查看您提供的日志表明数据库连接池关闭的原因是应用程序(播放)已关闭。

Play documentation中所述:

  

运行start命令时,Play会分叉新的JVM并运行默认的Netty HTTP服务器。标准输出流被重定向到Play控制台,因此您可以监视其状态。

     

服务器的进程ID在引导程序中显示并写入RUNNING_PID文件。要杀死正在运行的Play服务器,只需将SIGTERM发送到进程即可正确关闭应用程序。

     

如果您键入Ctrl + D,Play控制台将退出,但创建的服务器进程将继续在后台运行。然后关闭分叉的JVM标准输出流,并从logs / application.log文件中读取日志记录。

因此,进程可能已收到SIGTERM信号,Play应用程序以play run而不是play start启动,而有人在控制台上使用 Ctrl + D 或者服务器正在终止该进程,因为它的内存不足,可能会或可能不会指示应用程序中的内存泄漏,请参阅OOM killer

  

在极度低内存条件下,内存不足(OOM)杀手开始使用随着时间推移而演变的一组启发式选择杀死进程。

我建议您分析您的应用程序/监视服务器内存(您还可以检查服务器日志以查看内核是否已杀死任何进程)。

如果你能够扩展HikariCPModule并覆盖close方法,你可以添加一个记录器调用来打印当前的线程堆栈跟踪并验证实际调用的是什么,例如。关闭钩子或其他东西。

  override def close(dataSource: DataSource) = {
    Logger.info("Shutting down connection pool.")
    Thread.dumpStack()
    dataSource match {
      case ds: HikariDataSource => ds.close()
      case _ => sys.error("Unable to close data source: not a HikariDataSource")
    }

为“com.zaxxer.hikari”和Play启用DEBUG日志记录可能有助于进一步诊断数据库设置/应用程序的错误。

祝你好运!

答案 1 :(得分:1)

所以我发现了一段时间我的问题是什么。这真的很蠢。

我没有使用nohup命令启动我的应用。因此,操作系统使用SIGTERM消息终止了应用程序。

这完全与我的应用无关......

所以基本上,nohup将输出输出到dev>空

生活和学习。

答案 2 :(得分:0)

您可能希望删除minimumIdle配置,因为建议将其设置为HikariCP的默认值

hikaricp.minimumIdle = 0

HikariCP reference

另外,请检查您的连接池大小是否足够好。