演员上的scala.MatchError

时间:2019-07-13 12:48:53

标签: scala akka akka-typed

在测试过程中,我收到以下错误消息:

[ERROR] [07/13/2019 14:25:39.659] [DetectorSystem3-akka.io.pinned-dispatcher-2] [akka://DetectorSystem3/user/DetectorSupervisor] SapActiveConfirmed (of class com.sweetsoft.detector.ServerMonitoring$SapActiveConfirmed$)
scala.MatchError: SapActiveConfirmed (of class com.sweetsoft.detector.ServerMonitoring$SapActiveConfirmed$)
    at com.sweetsoft.detector.DetectorStateMachine$.$anonfun$create$2(DetectorStateMachine.scala:20)
    at akka.actor.typed.internal.BehaviorImpl$ReceiveMessageBehavior.receive(BehaviorImpl.scala:53)
    at akka.actor.typed.Behavior$.interpret(Behavior.scala:437)
    at akka.actor.typed.Behavior$.interpretMessage(Behavior.scala:393)
    at akka.actor.typed.internal.adapter.ActorAdapter.handleMessage(ActorAdapter.scala:121)
    at akka.actor.typed.internal.adapter.ActorAdapter.aroundReceive(ActorAdapter.scala:102)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:612)
    at akka.actor.ActorCell.invoke(ActorCell.scala:581)
    at akka.testkit.CallingThreadDispatcher.process$1(CallingThreadDispatcher.scala:280)
    at akka.testkit.CallingThreadDispatcher.runQueue(CallingThreadDispatcher.scala:313)
    at akka.testkit.CallingThreadDispatcher.dispatch(CallingThreadDispatcher.scala:234)
    at akka.actor.dungeon.Dispatch.sendMessage(Dispatch.scala:158)
    at akka.actor.dungeon.Dispatch.sendMessage$(Dispatch.scala:152)
    at akka.actor.ActorCell.sendMessage(ActorCell.scala:447)

我使用的是akka型,我认为它不应该这样。

actor的实现如下:

object DetectorStateMachine {

  case class State(kafka: ServerHealthEvent, sap: ServerHealthEvent)

  def create(informant: ActorRef[InformantEvent]): Behavior[ServerHealthEvent] =
    Behaviors.setup { context =>

      context.log.info(s"=============> Start DetectorStateMachine <=============")

      def loop(state: State): Behavior[ServerHealthEvent] = {

        Behaviors.receiveMessage {
          case KafkaActiveConfirmed
            if state.kafka == KafkaActiveConfirmed || state.sap == SapActiveConfirmed =>
            informant ! ServerOnlineConfirmed
            loop(state)
          case k@KafkaActiveConfirmed if state.kafka == KafkaInactiveConfirmed =>
            loop(State(k, state.sap))
          case k@KafkaInactiveConfirmed =>
            informant ! ServerOfflineConfirmed
            loop(State(k, state.sap))
          case SapActiveConfirmed
            if state.sap == SapActiveConfirmed && state.kafka == KafkaActiveConfirmed =>
            informant ! ServerOnlineConfirmed
            loop(state)
          case s@SapActiveConfirmed if state.sap == SapInactiveConfirmed =>
            loop(State(state.kafka, s))
          case s@SapInactiveConfirmed =>
            informant ! ServerOfflineConfirmed
            loop(State(state.kafka, s))
        }

      }

      loop(State(KafkaInactiveConfirmed, SapInactiveConfirmed))


    }

}

并且该测试的实现方式为:

final class DetectorSpec extends BddSpec {

  private val sap = new SapMock()
    .withExposedPorts(8080)
    .waitingFor(Wait.forHttp("/"))

  private val kafka = new KafkaContainer("5.2.1")

  sap.start()
  kafka.start()

  override def afterAll(): Unit = {
    sap.stop()
    kafka.stop()
  }

  private def withKafkaOfflineSapOnline(testCode: TestProbe[ServerEvent] => Unit)
  : Unit = {

    val config = ConfigFactory.parseString(
      s"""akka.actor.default-dispatcher = {
            type = akka.testkit.CallingThreadDispatcherConfigurator
          }
          akka.actor.testkit.typed.single-expect-default = 0s
          kafka {
            servers = "PLAINTEXT://localhost:9092"
          }
          sap {
            server = "ws://${sap.getContainerIpAddress}:${sap.getMappedPort(8080)}"
          }""")

    val testKit = ActorTestKit("DetectorSystem3", config)
    val inbox = testKit.createTestProbe[ServerEvent]("Receiver")
    testKit.spawn(DetectorSupervisor.create(), "DetectorSupervisor")
    testKit.system.receptionist ! Receptionist.Register(ServerStateKey, inbox.ref)

    testCode(inbox)
    testKit.shutdownTestKit()
  }

    scenario("SAP is online and Kafka is offline") {
      withKafkaOfflineSapOnline { inbox =>
        Given("I am waiting for the current state message")
        When("I am receive the state message")
        val msg = inbox.receiveMessage(60.second)
        Then("it should contain `Kafka is offline`")
        msg should be(ServerOfflineApproved)
      }
    }

  }
} 

我在做什么错了?

2 个答案:

答案 0 :(得分:1)

好吧,您有两个SapActiveConfirmed分支:

case SapActiveConfirmed
  if state.sap == SapActiveConfirmed && state.kafka == KafkaActiveConfirmed =>
  ...
case s@SapActiveConfirmed if state.sap == SapInactiveConfirmed =>
  ...

因此,如果两个条件都不成立(例如stateState(KafkaInactiveConfirmed, SapActiveConfirmed)),那么您将获得MatchErrorwithKafkaOfflineSapOnline当然听起来可以产生这种状态...

如果您以不同的方式构造匹配项,可能会有所帮助:

Behaviors.receiveMessage {
  case KafkaActiveConfirmed =>
    ...
  case KafkaInactiveConfirmed =>
    ...
  ...
}

条件进入分支机构的内部。

答案 1 :(得分:0)

如果要避免匹配错误-最好添加带有错误打印输出的后备空白案例