Scala 可以从非参与者与远程参与者通信吗?

Scala 可以从非参与者与远程参与者通信吗?,scala,akka,Scala,Akka,我知道,如果您使用询问(?语法),您可以发送消息并接收来自外部参与者的响应。问题是,我不知道当演员是远程演员时,这是否可以做到。我所说的“演员之外”是指普通的非演员代码。非参与者能否与远程参与者对话 []是流程边界,资本化意味着它是参与者。以前的设置是这样的,运行良好: [aB] 但是,现在我正在尝试使B远程: [a][B] 如果我给[a]一个本地演员,我可能会让它发挥作用,但这应该不是必要的 在a中没有ActorContext,只有ActorSystem。下面是我试图使用的代码(remotei

我知道,如果您使用
询问
语法),您可以发送消息并接收来自外部参与者的响应。问题是,我不知道当演员是远程演员时,这是否可以做到。我所说的“演员之外”是指普通的非演员代码。非参与者能否与远程参与者对话

[]是流程边界,资本化意味着它是参与者。以前的设置是这样的,运行良好:

[aB]

但是,现在我正在尝试使B远程:

[a][B]

如果我给[a]一个本地演员,我可能会让它发挥作用,但这应该不是必要的

a中没有
ActorContext
,只有
ActorSystem
。下面是我试图使用的代码(
remote
isB):

正如您所看到的,即使是语法也没有多大意义:已经有了一个
actorSystem
,但是在协议字符串中需要使用
systemName

是否可以从非参与者与远程参与者通信?我还没有找到任何可供参考的例子

我确实知道,B正在运行,事实上它已经有另一个演员能够找到它并与它交流

为了回答这个问题,我刚刚建立了一个独立的Scala程序,该程序创建了一个actor,并尝试将actorRef设置为B,方式与上面的代码类似。但没有快乐:

Actor not found for: ActorSelection[Anchor(akka://THIS_UNIVERSE/deadLetters), Path(/user/MyPLC)]
在这种情况下,这个独立程序是否需要有一个
application.conf
可供加载?i、 没有这样一个文件,它将无法找到远程参与者

很好-当sbt接收到
src/main/resources/application.conf
文件时,独立程序可以找到远程参与者

所以回到原来的问题:[a]根据定义,它的类路径中不会有
application.conf
文件,因为它不是参与者。不过我会放一个进去看看是否有帮助

那有帮助!在本例中,
application.conf
被放在一个依赖jar文件的根目录下


因此,问题的答案是,您可以从非参与者进行通信,但是您仍然需要参与者的大部分内容—参与者jar文件和类路径上的
application.conf

是的,你应该能够

如果您能够从本地参与者到远程参与者[a][B]进行通信,请B向a发送消息,然后打印发件人的路径,以确保您拥有正确的路径

关于语法,
systemName
是远程参与者系统的名称
actorSystem
在您的示例中是本地actor系统

您可以让非参与者代码向本地参与者询问远程参与者的引用。例如:

val remoteRefFuture = A ? GetRemoteAddress
remoteRefFuture.mapTo[ActorRef].foreach { B => B ! Xyz }  
仔细检查路径中的IP地址,确保它与远程端的远程处理配置中使用的IP地址或主机名完全匹配

下面是一个小的可运行示例。运行此应用程序的两个实例。使用命令行参数
2550
启动第一个。然后用
2551
开始第二个步骤

import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import akka.pattern.ask
import akka.util.Timeout

import scala.concurrent.Await
import scala.util.Success
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object AskRemote extends App {
  val port = args(0).toInt
  val configStr =
    s"""
       |akka {
       |  actor {
       |    provider = "akka.remote.RemoteActorRefProvider"
       |  }
       |  remote {
       |    enabled-transports = ["akka.remote.netty.tcp"]
       |    netty.tcp {
       |      hostname = "localhost"
       |      port = $port
       |    }
       |  }
       |}
      """.stripMargin
  val config = ConfigFactory.parseString(configStr)
  val system = ActorSystem(s"system$port", config)

  if (port == 2550) {
    system.actorOf(Props(new MyActor), "myActor")
    system.awaitTermination()

  } else {
    implicit val timeout = Timeout(5.seconds)
    val path = s"akka.tcp://system2550@localhost:2550/user/myActor"

    system.actorSelection(path).resolveOne().onComplete {
      case Success(ref) =>
        val fut = ref ? "hello"
        println(Await.result(fut, 5.seconds))
        system.shutdown()
    }
  }
}

class MyActor extends Actor {
  def receive = {
    case s: String =>
      println(s"got $s")
      sender() ! s"you sent $s"
      context.system.shutdown()
  }
}

在这里,你已经成为了一名演员。但是[a]只是一个正常的非参与者,需要访问[B]。[a] 这只是一个想要同步(使用
等待
)向[B]提问的过程,这是硬件。我不明白-你说的“大写表示它是一个参与者”,你的
str
路径示例是一个参与者的路径。我的建议是1)临时设置一个本地参与者,以验证远程路径是否正确,或者2)无论如何使用一个本地参与者作为远程代码和非参与者代码之间的中介。您将需要本地的actor系统来使用
ask
),让本地actor进行调解不会有什么坏处。只需添加一条关于确保路径中的IP地址正确的注释。a从未大写-它就像鼠标的UI。我认为答案是否定的,除非你采用一种变通方法,让一个本地演员参与进来。当我有[AB]的时候,我确实可以接触到一个本地演员——B。我现在失去了那个本地演员,但需要重新介绍它。我要问的问题是,是否有可能不需要重新介绍一些本地演员。我的意思是B.B是演员,对吧,不是真正的硬件?是的,可以从
ask
发送到远程参与者。您只需要确保路径是正确的。如果它不工作,则路径不正确。最简单的调试方法是创建一个本地参与者。
import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import akka.pattern.ask
import akka.util.Timeout

import scala.concurrent.Await
import scala.util.Success
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object AskRemote extends App {
  val port = args(0).toInt
  val configStr =
    s"""
       |akka {
       |  actor {
       |    provider = "akka.remote.RemoteActorRefProvider"
       |  }
       |  remote {
       |    enabled-transports = ["akka.remote.netty.tcp"]
       |    netty.tcp {
       |      hostname = "localhost"
       |      port = $port
       |    }
       |  }
       |}
      """.stripMargin
  val config = ConfigFactory.parseString(configStr)
  val system = ActorSystem(s"system$port", config)

  if (port == 2550) {
    system.actorOf(Props(new MyActor), "myActor")
    system.awaitTermination()

  } else {
    implicit val timeout = Timeout(5.seconds)
    val path = s"akka.tcp://system2550@localhost:2550/user/myActor"

    system.actorSelection(path).resolveOne().onComplete {
      case Success(ref) =>
        val fut = ref ? "hello"
        println(Await.result(fut, 5.seconds))
        system.shutdown()
    }
  }
}

class MyActor extends Actor {
  def receive = {
    case s: String =>
      println(s"got $s")
      sender() ! s"you sent $s"
      context.system.shutdown()
  }
}