Автоматический повтор на недоступных хостах (NoHostAvailableException) в Phantom DSL и Play! 2

В настоящее время я работаю над интеграцией Phantom DSL в небольшое приложение Play. Поскольку мы планируем запустить приложение в среде Docker, я использую Docker Compose на своем локальном компьютере для тестирования приложения.

Однако при одновременной загрузке экземпляра Cassandra и приложения Play он не может подключиться или работать, поскольку приложение Play доступно до Cassandra.

В настоящее время я настроил коннектор следующим образом:

object Defaults {
  val connector = ContactPoint(sys.env("CASSANDRA_URL"), sys.env("CASSANDRA_PORT").toInt)
    .withClusterBuilder(_.withSocketOptions(
      new SocketOptions().setTcpNoDelay(true))
    ).keySpace("my_app")
}

При инициализации базы данных следующим образом

class CassandraDB(val keyspace: KeySpaceDef) extends Database(keyspace) {
  object users extends ConcreteUsers with keyspace.Connector
  object articles extends ConcreteArticles with keyspace.Connector
  object comments extends ConcreteComments with keyspace.Connector
}


object CassandraDB extends CassandraDB(Defaults.connector)

И моя игра! контроллер делает вызовы базы данных, используя объект CassandraDB

def index = Action.async {
  CassandraDB.users.getAll.map { users =>
    Ok(Json.toJson(users))
  }
}

Первая попытка подключения к базе данных приводит к ожидаемому NoHostAvailableException.

com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: localhost/127.0.0.1:9042)

Любой запрос после этого вызовет следующее исключение:

play.api.UnexpectedException: Unexpected exception[RuntimeException: java.lang.NoClassDefFoundError: Could not initialize class models.CassandraDB$]

Как только это произойдет, для его работы требуется ручной перезапуск приложения.

Ожидание полной инициализации контейнера Cassandra работает нормально, это не кажется идеальным, и я надеялся повторить попытку после того, как ему не удалось подключиться.


person ivopatty    schedule 19.10.2016    source источник


Ответы (1)


Ну, мне ясно, что нет ничего плохого в фантоме и/или вашем приложении, верно? Оба работают нормально, когда контейнер работает правильно.

Вы пробовали заказать композицию?

https://docs.docker.com/compose/startup-order/

ИЗМЕНИТЬ

Основываясь на вопросе OP в моем ответе, возможным решением было бы использование подхода «Актер», где вы могли бы использовать стратегию супервизора в случае, если ваша база данных отсутствует.

override def supervisorStrategy: SupervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 5) {
      case _: NoHostAvailableException => Restart
      case _: Exception => Stop
    }

Таким образом, у вас может быть Актер, который взаимодействует с вашей базой данных, и при попытке подключения, если возникает известная ошибка, вы можете поймать ее на супервизоре и решить, что делать. Если вы решите перезапустить, вы можете использовать метод preRestart для повторного подключения.

override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    log.warning(s"Restarting Actor due: {}", reason.getMessage)
    //do something here
  }

http://doc.akka.io/docs/akka/2.4.11/general/supervision.html http://doc.akka.io/docs/akka/2.4.11/scala/fault-tolerance.html

person Thiago Pereira    schedule 19.10.2016
comment
Да, порядок запуска тоже реализован. Проблема заключается в том, что недоступная база данных требует ручного перезапуска приложения. Разве в Phantom или в моем приложении не должно быть возможности создать для этого устойчивость? - person ivopatty; 20.10.2016
comment
@ivopatty Я обновил свой ответ, взгляните на него и посмотрите, решит ли он вашу проблему. - person Thiago Pereira; 20.10.2016