Scala 通过代理参与者的DistributedPubSubMediator订阅不工作

Scala 通过代理参与者的DistributedPubSubMediator订阅不工作,scala,akka,Scala,Akka,我的同事和我一直对DistributedPubSubMediator直接或通过代理角色订阅/取消订阅的不同行为感到困惑。我们进行了一个测试,以显示下面不同的结果 根据我们的理解,ActorRef.forward应该传递给原始发送者,因此消息是直接发送给中介者还是通过代理参与者并不重要。即 为了解决这个问题,我们必须扩展DIstributedPubSubMediator类,并包括DIstributedPubSubMediator对象已经提供的逻辑。理想情况下,我们更愿意直接使用对象并还原代码 这好

我的同事和我一直对DistributedPubSubMediator直接或通过代理角色订阅/取消订阅的不同行为感到困惑。我们进行了一个测试,以显示下面不同的结果

根据我们的理解,ActorRef.forward应该传递给原始发送者,因此消息是直接发送给中介者还是通过代理参与者并不重要。即

为了解决这个问题,我们必须扩展DIstributedPubSubMediator类,并包括DIstributedPubSubMediator对象已经提供的逻辑。理想情况下,我们更愿意直接使用对象并还原代码

这好像是一个错误。有人知道这种不寻常行为的根本原因吗?请帮忙

[2013年10月22日]测试根据罗兰的回答(谢谢)进行更新,并在SubscriberAck和UnscriberAck上添加了expectMsgType。我们现在收到了订阅,但奇怪的是没有收到取消订阅。这不是一个大问题,但我们想知道原因

另一个问题是,如果我们可以一起问的话,通过运行在同一Actor系统中的代理Actor将远程Actor订阅到DistributedPubSubMediator是否是一种良好的做法

目前我们有:

  • 订阅应用程序发现发布应用程序(以非Akka方式)并获取群集地址
  • 远程订户使用此地址和已知代理角色的路径发送身份请求
  • 远程订户获得ActorIdentity响应,然后通过此(远程)代理订阅/取消订阅
  • 在发布者应用程序上,订阅/取消订阅消息被转发到DistributedPubSubMediator,用于发布后续业务消息 我们没有按照Akka Reactor pubsub chat客户端示例加入集群(即仅使用DistributedPubSubMediator发布),因为我们需要在发布服务器端处理故障转移

    [2013年11月5日]添加了发送消息测试。它似乎不起作用,我们还没有弄明白

    package star.common.pubsub
    
    import org.scalatest.{BeforeAndAfterAll, FunSuite}
    
    import org.junit.runner.RunWith
    
    import akka.contrib.pattern.DistributedPubSubExtension
    import akka.contrib.pattern.DistributedPubSubMediator._
    import akka.testkit.TestKit
    import akka.actor.{Actor, ActorSystem, ActorRef, Props}
    import scala.concurrent.duration._
    
    import com.typesafe.config.ConfigFactory
    
    object MediatorTest {
      val config = ConfigFactory.parseString(s"""
                                  akka.actor.provider="akka.cluster.ClusterActorRefProvider"
                                  akka.remote.netty.tcp.port=0
                                  akka.extensions = ["akka.contrib.pattern.DistributedPubSubExtension"]
                                  """)
    }
    
    @RunWith(classOf[org.scalatest.junit.JUnitRunner])
    class MediatorTest extends TestKit(ActorSystem("test", MediatorTest.config)) with FunSuite {
    
      val mediator = DistributedPubSubExtension(system).mediator
      val topic = "example"
      val message = "Published Message"
      //  val joinAddress = Cluster(system).selfAddress
      //  Cluster(system).join(joinAddress)
    
      test("Direct subscribe to mediator") {
        mediator.!(Subscribe(topic, testActor))(testActor)
        expectMsgType[SubscribeAck](5 seconds)
    
        mediator.!(Publish(topic, message))(testActor)
        expectMsg(2 seconds, message)
    
        mediator.!(Unsubscribe(topic, testActor))(testActor)
        expectMsgType[UnsubscribeAck](5 seconds)
    
        mediator ! Publish(topic, message)
        expectNoMsg(2 seconds)
      }
    
    
      test("Subscribe to mediator via proxy") {
        class Proxy extends Actor {
          override def receive = {
            case subscribe: Subscribe =>
              mediator forward subscribe
    
            case unsubscribe: Unsubscribe =>
              mediator forward unsubscribe
    
            case publish: Publish =>
              mediator.!(publish)
          }
        } 
    
        val proxy = system.actorOf(Props(new Proxy), "proxy")
    
        proxy.!(Subscribe(topic,testActor))(testActor)
        expectMsgType[SubscribeAck](2 seconds)
    
        proxy ! Publish(topic, message)
        expectMsg(5 seconds, message)
    
        proxy.!(Unsubscribe(topic,testActor))(testActor)
        expectMsgType[UnsubscribeAck](5 seconds)
    
        proxy ! Publish(topic, message)
        expectNoMsg(5 seconds)
      }
    
      test("Send message to address") {
    
        val testActorAddress = testActor.path.toString
        //    val system2 = ActorSystem("test", MediatorTest.config)
        //    Cluster(system2).join(joinAddress)
    
        mediator.!(Subscribe(topic, testActor))(testActor)
        expectMsgType[SubscribeAck](5 seconds)
    
        println(testActorAddress) // akka://test/system/testActor1
    
        mediator.!(Publish(topic, message))(testActor)
        expectMsg(2 seconds, message)
    
        mediator ! Send(testActorAddress, message, false)
    
        expectMsg(5 seconds, message)
      }
    }
    
    两件事:

    • 您是否使用
      转发
      并不重要,因为您的测试过程中没有一个有用的发送器(您没有混入
      隐式发送器
      );但这不是问题所在
    • 您没有转发
      Publish
      消息,这就是它没有发布消息的原因

    谢谢罗兰,我已根据您的反馈更新了上述测试。收到消息和SubscribeAck,但未收到UnscribeAck。我还添加了关于我们的实现的更多信息,以反馈我们使用代理演员是否走上了正确的道路。您是否尝试过akka.actor.debug.unhandled,或者是否存在死信?嗨,罗兰,我有,但遗憾的是,DistributedPubSubMediator部分没有太多日志记录。今天我们发现DistributedPubSubMediator.Send也不适用于我们。我已经更新了测试。解决方法是传递ActorRef并绕过中介直接发送给它。我读到传递ActorRef不是一个好主意,但它似乎是我们现在唯一的选择。我不明白为什么“传递ActorRef”应该是一个坏主意,它们被设计为在消息中发送。我刚刚注意到,在你的问题中,你链接到了错误的文档(对于Scala演员);你确定你没有把scala.actors.ActorRef和akka.actor.ActorRef混为一谈吗?嗨,罗兰,是的,你是对的。谢谢你指出这一点。我们还发现测试中的发送不起作用,因为我们没有完成Put。:)