我能够使Play应用加入现有的Akka集群,然后对在另一个ActorSystem上运行的actor进行询问,并返回结果。但是我遇到了一些麻烦-
当播放尝试加入集群时,我会在日志中看到以下内容。我怀疑Play正在启动自己的Akka集群吗?我真的不确定这意味着什么。
无法通过
name=akka:type=Cluster
注册集群JMX MBean,因为它已经被注册。如果您运行多个集群 在同一个JVM中,在配置中将“ akka.cluster.jmx.multi-mbeans-in-same-jvm = on”设置为
现在,每次请求到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}
}
答案 0 :(得分:0)
答案
请参阅此URL。 https://www.playframework.com/documentation/2.6.x/ScalaAkka#Built-in-actor-system-name包含有关配置actor系统名称的详细信息。
您不应在每个请求上初始化actor系统,请在Application类中使用Play注入的actor系统,如果要自定义Actor系统,则应通过修改AKKA配置来实现。为了那个原因, 您应该创建自己的扩展GuiceApplicationLoader的ApplicationLoader并重写builder方法以具有自己的AKKA配置。 Play照顾的其他事情,例如在您的Application中注入这个actor系统。
请参阅下面的URL