В моем случае у меня есть 2 стороны:Akka: тестирование мониторинг смерть смотреть
watchee
(я используюTestProbe
)watcher
(Watcher
заворачивают вTestActorRef
выставить некоторые внутренниеstate
я отслеживать в моем тесте)
Наблюдатель должен предпринять некоторые действия, когда watchee
умирает.
Вот полный тест я написал до сих пор:
class TempTest(_system: ActorSystem) extends TestKit(_system) with ImplicitSender with FunSuiteLike with Matchers with BeforeAndAfterAll {
def this() = this(ActorSystem("TempTest"))
override def afterAll {
TestKit.shutdownActorSystem(system)
}
class WatcherActor(watchee: ActorRef) extends Actor {
var state = "initial"
context.watch(watchee)
override def receive: Receive = {
case "start" =>
state = "start"
case _: Terminated =>
state = "terminated"
}
}
test("example") {
val watchee = TestProbe()
val watcher = TestActorRef[WatcherActor](Props(new WatcherActor(watchee.ref)))
assert(watcher.underlyingActor.state === "initial")
watcher ! "start" // "start" will be sent and handled by watcher synchronously
assert(watcher.underlyingActor.state === "start")
system.stop(watchee.ref) // will cause Terminated to be sent and handled asynchronously by watcher
Thread.sleep(100) // what is the best way to avoid blocking here?
assert(watcher.underlyingActor.state === "terminated")
}
}
Теперь, поскольку все заинтересованные субъекты используют CallingThreadDispatcher
(все тестовые хелперы AKKA ныряет построены с использованием реквизита с .withDispatcher(CallingThreadDispatcher.Id)
), я могу с уверенностью предположить, что, когда это утверждение возвращает:
watcher ! "start"
... «Пуск» сообщение уже обработано WatchingActor
и, таким образом, я могу сделать утверждение, основанное на watcher.underlyingActor.state
Однако, основываясь на моих наблюдениях, когда я перестану watchee
с помощью system.stop
или отправив Kill
к нему Terminated
сообщению, полученное в качестве побочного эффекта от watchee
смерти получает асинхронно, в другом потоке.
Not-a-solution должен остановить watchee
, заблокировать поток в течение некоторого времени и подтвердить состояние Watcher
после этого, но я хотел бы знать, как правильно это сделать (то есть, как быть уверенным, что после убийства актер его наблюдатель получил и обработалTerminated
сообщение сигнализация это смерть)?
Пробовал ваш сниппет, и это сработало. Самое смешное в том, что он страдает почти той же проблемой, что и исходный ответ @ cmbaxter (ожидающий результата «gracefulStop» гарантирует возвращение после «posStop» целевого актера, а не «Terminated», произведенный смертью целевого актера, потребляется) , Я наклонился, пытаясь понять, почему ваша отрезанная работа, и оказалось, что это не «gracefulStop», что заставляет ее работать, а то, что вы отправляете «PoisonPill» для прекращения действия актера. –
По какой-то причине «Terminated», созданный смертью актера от «PoisonPill», обрабатывается синхронно, а те, которые производятся смертью из «Kill» или «system.stop» - асинхронно. Я еще не понял, почему, но в конце концов это означает, что можно просто отправить «PoisonPill» в «watchee» для достижения моей цели (зная, когда актер умер, и все «наблюдатели» были признаны), и что 'gracefulStop' не имеет ничего общего с решением этой проблемы (фактически, используя' gracefulStop' и 'Kill', поскольку сообщение вводит условие гонки, о котором я говорил в комментарии выше). –
Я тоже не уверен. Может быть, это потому, что Kill бросает исключение, а PPill этого не делает? –