Slick + HikariCP + Play 导致 Postgres 在经常重启 Play 后 运行 断开连接

Slick + HikariCP + Play is causing Postgres to run out of connections after often restarting Play

我正在使用 Slick 和 HikariCP 开发一个用于连接池的 Play 应用程序。重新启动 Play 几次后,我的开发 Postgres 服务器用完连接并显示,

db_1  | 2019-11-19 21:06:46.583 GMT [395] FATAL:  remaining connection slots are reserved for non-replication superuser connections
db_1  | 2019-11-19 21:06:46.886 GMT [396] FATAL:  remaining connection slots are reserved for non-replication superuser connections
db_1  | 2019-11-19 21:06:48.167 GMT [397] FATAL:  remaining connection slots are reserved for non-replication superuser connections

我用 SQL 查询 SELECT state, COUNT(*) FROM pg_stat_activity GROUP BY state; 进行了监控,空闲连接数似乎确实在迅速增加。我想解决这个问题,这样我就不会在开发或生产中出现泄漏连接。

关于如何修复空闲连接泄漏的任何建议?

设置

build.sbt

我的 build.sbt 具有以下依赖关系,

      "com.typesafe.play" %% "play-slick" % "4.0.2",
      "com.typesafe.play" %% "play-slick-evolutions" % "4.0.2",
      "com.typesafe.slick" %% "slick-codegen" % "3.3.2",
      "com.typesafe.slick" %% "slick" % "3.3.2",
      "org.slf4j" % "slf4j-nop" % "1.7.26",
      "com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
      "org.postgresql" % "postgresql" % "42.2.8",

Application.conf

我的 postgres 配置存储在我的 application.conf

slick {
  dbs {
    default {
      profile="slick.jdbc.PostgresProfile$"
      db {
        connectionPool = "HikariCP" //use HikariCP for our connection pool
        profile = "org.postgresql.Driver"
        dataSourceClass = "org.postgresql.ds.PGSimpleDataSource" //Simple datasource with no connection pooling. The connection pool has already been specified with HikariCP.
        properties = {
          serverName = "localhost"
          portNumber = "5432"
          databaseName = "website"
          user = "websiteserver"
          password = "397c9140fb0e2424396510b8d6e29a07aa1a92420027d3750ef1faed87bb617a"
        }
      }
      numThreads = 10
      connectionTimeout = 6000 // In the hope that this resolves the connection errors.
      leakDetectionThreshold=60000 // In the hope that this resolves the connection errors.
    }
  }
}

播放应用程序

在我的 play 2.7.3 应用程序中,我使用

加载数据库配置
@Singleton
class PersonRepositoryImpl @Inject() ()(implicit ec: PersonExecutionContext)
  extends PersonRepository {
  // We want the JdbcProfile for this provider
  private val db = Database.forConfig("slick.dbs.default.db")
  private val persons = TableQuery[PersonTable]

  def create(p: Person)(implicit mc: MarkerContext): Future[PersonData] = db.run {
  // Some operations on persons
  } 
}

我尝试了许多不同的配置,但 none 似乎解决了我面临的连接泄漏问题。

当您需要它作为依赖项时,您正在调用 Database.forConfig 作为私有 val。您应该利用 play-slick 来依赖注入数据库配置提供程序:

@Singleton
class PersonRepository @Inject() (dbConfigProvider: DatabaseConfigProvider)(implicit ec: ExecutionContext) {
  // We want the JdbcProfile for this provider
  private val dbConfig = dbConfigProvider.get[JdbcProfile]

   ...
}

https://github.com/playframework/play-samples/blob/2.8.x/play-scala-slick-example/app/models/PersonRepository.scala#L15

另见 documentation:

While you can get the DatabaseConfig instance manually by accessing the SlickApi, we’ve provided some helpers for runtime DI users (Guice, Scaldi, Spring, etc.) for obtaining specific instances within your controller.

Here is an example of how to inject a DatabaseConfig instance for the default database (i.e., the database named default in your configuration):

class Application @Inject() (protected val dbConfigProvider: DatabaseConfigProvider, cc: ControllerComponents)(
    implicit ec: ExecutionContext
) extends AbstractController(cc)
    with HasDatabaseConfigProvider[JdbcProfile] {
}