Play + Akka-加入集群并在另一个ActorSystem上询问actor

时间:2018-06-27 16:44:23

标签: scala playframework akka akka-cluster

我能够使Play应用加入现有的Akka集群,然后对在另一个ActorSystem上运行的actor进行询问,并返回结果。但是我遇到了一些麻烦-

  1. 当播放尝试加入集群时,我会在日志中看到以下内容。我怀疑Play正在启动自己的Akka集群吗?我真的不确定这意味着什么。

      

    无法通过name=akka:type=Cluster注册集群JMX MBean,因为它已经被注册。如果您运行多个集群   在同一个JVM中,在配置中将“ akka.cluster.jmx.multi-mbeans-in-same-jvm = on”设置为

  2. 现在,每次请求到Controller时,我都会重新初始化actorsystem,我知道这样做是不正确的。我是Scala,Akka和Play的新手,很难弄清楚如何使它成为Singleton服务并注入到我的控制器中。

到目前为止,我已经知道了-

class DataRouter @Inject()(controller: DataController) extends SimpleRouter {
  val prefix = "/v1/data"

  override def routes: Routes = {
    case GET(p"/ip/$datatype") =>
      controller.get(datatype)

    case POST(p"/ip/$datatype") =>
      controller.process

  }

} 

case class RangeInput(start: String, end: String)
object RangeInput {

  implicit val implicitWrites = new Writes[RangeInput] {
    def writes(range: RangeInput): JsValue = {
      Json.obj(
        "start" -> range.start,
        "end" -> range.end

      )
    }
  }
}

@Singleton
class DataController @Inject()(cc: ControllerComponents)(implicit exec: ExecutionContext) extends AbstractController(cc) {

  private val logger = Logger("play")
  implicit val timeout: Timeout = 115.seconds
  private val form: Form[RangeInput] = {
    import play.api.data.Forms._

    Form(
      mapping(
        "start" -> nonEmptyText,
        "end" -> text
      )(RangeInput.apply)(RangeInput.unapply)
    )
  }


  def get(datatype: String): Action[AnyContent] = Action.async { implicit request =>
    logger.info(s"show: datatype = $datatype")
    logger.trace(s"show: datatype = $datatype")
    //val r: Future[Result] = Future.successful(Ok("hello " + datatype ))
    val config = ConfigFactory.parseString("akka.cluster.roles = [gateway]").
      withFallback(ConfigFactory.load())
    implicit val system: ActorSystem = ActorSystem(SharedConstants.Actor_System_Name, config)
    implicit val materializer: ActorMaterializer = ActorMaterializer()
    implicit val executionContext = system.dispatcher

    val ipData = system.actorOf(
      ClusterRouterGroup(RandomGroup(Nil), ClusterRouterGroupSettings(
        totalInstances = 100, routeesPaths = List("/user/getipdata"),
        allowLocalRoutees = false, useRoles = Set("static"))).props())

    val res: Future[String] = (ipData ? datatype).mapTo[String]
    //val res: Future[List[Map[String, String]]] = (ipData ? datatype).mapTo[List[Map[String,String]]]
    val futureResult: Future[Result] = res.map { list =>
      Ok(Json.toJson(list))
    }
    futureResult
  }

  def process: Action[AnyContent] = Action.async { implicit request =>
    logger.trace("process: ")
    processJsonPost()
  }

  private def processJsonPost[A]()(implicit request: Request[A]): Future[Result] = {
    logger.debug(request.toString())
    def failure(badForm: Form[RangeInput]) = {
      Future.successful(BadRequest("Test"))
    }

    def success(input: RangeInput) = {
      val r: Future[Result] = Future.successful(Ok("hello " + Json.toJson(input)))
      r
    }

    form.bindFromRequest().fold(failure, success)
  }

}

akka {
  log-dead-letters = off
  log-dead-letters-during-shutdown = off
  actor {
    provider = "akka.cluster.ClusterActorRefProvider"
  }
  remote {
    log-remote-lifecycle-events = off
    enabled-transports = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = ${myhost}
      port = 0
    }
  }
  cluster {
    seed-nodes = [
      "akka.tcp://MyCluster@localhost:2541"
    ]

} seed-nodes = ${?SEEDNODE}
}

1 个答案:

答案 0 :(得分:0)

答案

  1. 请参阅此URL。 https://www.playframework.com/documentation/2.6.x/ScalaAkka#Built-in-actor-system-name包含有关配置actor系统名称的详细信息。

  2. 您不应在每个请求上初始化actor系统,请在Application类中使用Play注入的actor系统,如果要自定义Actor系统,则应通过修改AKKA配置来实现。为了那个原因, 您应该创建自己的扩展GuiceApplicationLoader的ApplicationLoader并重写builder方法以具有自己的AKKA配置。 Play照顾的其他事情,例如在您的Application中注入这个actor系统。

请参阅下面的URL

https://www.playframework.com/documentation/2.6.x/ScalaDependencyInjection#Advanced:-Extending-the-GuiceApplicationLoader