Воспроизвести тесты с базой данных: "Слишком много подключений"

Для того, чтобы база данных была доступной в масштабе с эволюцией, я использую это расширение по умолчанию PlaySpec вдохновлен этим так вопрос:

trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
  lazy val appBuilder = new GuiceApplicationBuilder()
  lazy val injector = appBuilder.injector()
  lazy val databaseApi = injector.instanceOf[DBApi]

  override def beforeAll() = {
    Evolutions.applyEvolutions(databaseApi.database("default"))
  }

  override def afterAll() = {
    Evolutions.cleanupEvolutions(databaseApi.database("default"))
    databaseApi.database("default").shutdown()
  }
}

Он применяет эволюцию базы данных при запуске пакета и отменяет его при завершении пакета. Тест выглядит так

class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ...

После добавления дополнительных тестов, таких как этот, я попал в точку, когда некоторые тесты, которые выполняются успешно, когда я запускаю их один, терпят неудачу с этой ошибкой:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: источник данных отклонил установление соединения, сообщение от сервера: "Слишком много соединений"

Как видно из приведенного выше кода, я попытался добавить строку

databaseApi.database("default").shutdown()

в afterAll() чтобы смягчить это, но это не имело никакого эффекта. Я пытался не запускать тесты параллельно, но и безрезультатно. Где я открываю соединения БД, не закрывая их, и куда мне звонить shutdown()?

NB Я использую Play 2.5.10 и Slick 3.1.

2 ответа

У меня есть много тестов (около 500), и я не получаю эту ошибку, единственное отличие, которое я имею с вашим кодом, заключается в том, что я добавляю

databaseApi.database("default").getConnection().close()

а также

Play.stop(fakeApplication)

для интеграционных испытаний.

Дайте мне знать, если это что-то изменит.

Хотя это не отвечает на то, что происходит с утечкой соединений, мне наконец удалось взломать это:

  1. Добавьте jdbc к вам libraryDependencies, даже если FAQ по Play-Slick говорит вам не делать этого:

    # build.sbt
    libraryDependencies += jdbc
    

    Перезапустите sbt, чтобы изменения вступили в силу. В IntelliJ вы также захотите обновить проект.

  2. Отключите модуль JDBC, который конфликтует с Play-Slick (кредиты: этот SO ответ):

    # application.conf
    play.modules.disabled += "play.api.db.DBModule"
    

    В том же месте вы уже должны были настроить что-то вроде

    slick {
      dbs {
        default {
          driver = "slick.driver.MySQLDriver$"
          db.driver = "com.mysql.jdbc.Driver"
          db.url = "jdbc:mysql://localhost/test"
          db.user = "sa"
          db.password = ""
        }
      }
    }
    
  3. Теперь вы можете использовать play.api.db.Databases из JDBC и его метод withDatabase запустить эволюции.

    import org.scalatest.BeforeAndAfterAll
    import org.scalatestplus.play.PlaySpec
    import play.api.db.{Database, Databases}
    import play.api.db.evolutions.Evolutions
    
    
    trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll {
    
      /**
       * Here we use Databases.withDatabase to run evolutions without leaking connections.
       * It slows down the tests considerably, though.
       */
    
      private def withTestDatabase[T](block: Database => T) = {
        Databases.withDatabase(
          driver = "com.mysql.jdbc.Driver",
          url = "jdbc:mysql://localhost/test",
          name = "default",
          config = Map(
            "username" -> "sa",
            "password" -> ""
          )
        )(block)
      }
    
      override def beforeAll() = {
        withTestDatabase { database =>
          Evolutions.applyEvolutions(database)
        }
      }
    
      override def afterAll() = {
        withTestDatabase { database =>
          Evolutions.cleanupEvolutions(database)
        }
      }
    
    }
    
  4. Наконец, вызовите тесты, требующие сброса БД, например:

    class MySpec extends ResetDbSpec {...}
    

Конечно, это отстой, повторяя эту конфигурацию как в "application.test.conf", так и в withDatabase() Кроме того, он смешивает два разных API, не говоря уже о производительности. Также он добавляет это до и после каждого пакета, что раздражает:

[info] application - Создание пула для источника данных по умолчанию
Приложение [info] - Выключение пула соединений.

Если у кого-то есть лучшее предложение, пожалуйста, улучшите этот ответ! Я боролся в течение нескольких месяцев.

Другие вопросы по тегам