Воспроизвести тесты с базой данных: "Слишком много подключений"
Для того, чтобы база данных была доступной в масштабе с эволюцией, я использую это расширение по умолчанию 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)
для интеграционных испытаний.
Дайте мне знать, если это что-то изменит.
Хотя это не отвечает на то, что происходит с утечкой соединений, мне наконец удалось взломать это:
Добавьте jdbc к вам libraryDependencies, даже если FAQ по Play-Slick говорит вам не делать этого:
# build.sbt libraryDependencies += jdbc
Перезапустите sbt, чтобы изменения вступили в силу. В IntelliJ вы также захотите обновить проект.
Отключите модуль 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 = "" } } }
Теперь вы можете использовать
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) } } }
Наконец, вызовите тесты, требующие сброса БД, например:
class MySpec extends ResetDbSpec {...}
Конечно, это отстой, повторяя эту конфигурацию как в "application.test.conf", так и в withDatabase()
Кроме того, он смешивает два разных API, не говоря уже о производительности. Также он добавляет это до и после каждого пакета, что раздражает:
[info] application - Создание пула для источника данных по умолчанию
Приложение [info] - Выключение пула соединений.
Если у кого-то есть лучшее предложение, пожалуйста, улучшите этот ответ! Я боролся в течение нескольких месяцев.