当我们说Actor生命周期的时候,我们能看到Actor能被很多种方式停掉(用ActorSystem.stop或ActorContext.stop或发送一个PoisonPill - 也有一个killgracefulstop)。

无论Actor是怎么死的,有些情况一些系统中的其他actor想要知道。让我们举一个Actor与数据库交互的例子 - 我们叫它RepositoryActor。很明显,会有一些其他actor会向这个RepositoryActor发送消息。这些有“兴趣”的Actor很愿意留个eye或者看(watch)这个actor关闭时的消息。这个在Actor里面叫DeathWatch。这个用来watchunwatch的方法就是ActorContext.watchActorContext.unwatch。如果已经监视了,这些watcher会在Actor关闭时收到一个Terminated消息,并可以很舒服的加到他们的receive功能中。

不像Supervision有一个严格的父子继承关系,任何Actor都可以watch任何ActorSystem中的Actor。

让我们看下。

代码

QUOTEREPOSITORYACTOR

1.我们的QueryRepositoryActor格言查询Actor保存了一个quote的列表并且在收到一个QuoteRepositoryRequest时随机返回一条。

  1. 他记录了收到消息的个数,如果收到超过3个消息,他用PoisonPill把自己杀掉

这没啥神奇的。

  1. package me.rerun.akkanotes.deathwatch
  2. import akka.actor.{PoisonPill, Actor, ActorLogging, actorRef2Scala}
  3. import me.rerun.akkanotes.protocols.QuoteRepositoryProtocol._
  4. import scala.util.Random
  5. class QuoteRepositoryActor() extends Actor with ActorLogging {
  6. val quotes = List(
  7. "Moderation is for cowards",
  8. "Anything worth doing is worth overdoing",
  9. "The trouble is you think you have time",
  10. "You never gonna know if you never even try")
  11. var repoRequestCount:Int=1
  12. def receive = {
  13. case QuoteRepositoryRequest => {
  14. if (repoRequestCount>3){
  15. self!PoisonPill
  16. }
  17. else {
  18. //Get a random Quote from the list and construct a response
  19. val quoteResponse = QuoteRepositoryResponse(quotes(Random.nextInt(quotes.size)))
  20. log.info(s"QuoteRequest received in QuoteRepositoryActor. Sending response to Teacher Actor $quoteResponse")
  21. repoRequestCount=repoRequestCount+1
  22. sender ! quoteResponse
  23. }
  24. }
  25. }
  26. }

TEACHERACTORWATCHER

一样的,TeacherActorWatcher也没啥神奇的,除了他创建了一个QuoteRepositoryActor并且用context.watch观察。

  1. package me.rerun.akkanotes.deathwatch
  2. import akka.actor.{Terminated, Props, Actor, ActorLogging}
  3. import me.rerun.akkanotes.protocols.TeacherProtocol.QuoteRequest
  4. import me.rerun.akkanotes.protocols.QuoteRepositoryProtocol.QuoteRepositoryRequest
  5. class TeacherActorWatcher extends Actor with ActorLogging {
  6. val quoteRepositoryActor=context.actorOf(Props[QuoteRepositoryActor], "quoteRepositoryActor")
  7. context.watch(quoteRepositoryActor)
  8. def receive = {
  9. case QuoteRequest => {
  10. quoteRepositoryActor ! QuoteRepositoryRequest
  11. }
  12. case Terminated(terminatedActorRef)=>{
  13. log.error(s"Child Actor {$terminatedActorRef} Terminated")
  14. }
  15. }
  16. }

测试CASE

这里会有点意思。我从来没想过这个可以被测试。akka-testkit。我们会分析下这三个测试CASE:

1. 断言如果观察到已经收到Terminated消息

QuoteRepositoryActor应该在收到第四条消息时给测试case发送一条Terminated消息。前三条应该是可以的。

  1. "A QuoteRepositoryActor" must {
  2. ...
  3. ...
  4. ...
  5. "send back a termination message to the watcher on 4th message" in {
  6. val quoteRepository=TestActorRef[QuoteRepositoryActor]
  7. val testProbe=TestProbe()
  8. testProbe.watch(quoteRepository) //Let's watch the Actor
  9. within (1000 millis) {
  10. var receivedQuotes = List[String]()
  11. (1 to 3).foreach(_ => quoteRepository ! QuoteRepositoryRequest)
  12. receiveWhile() {
  13. case QuoteRepositoryResponse(quoteString) => {
  14. receivedQuotes = receivedQuotes :+ quoteString
  15. }
  16. }
  17. receivedQuotes.size must be (3)
  18. println(s"receiveCount ${receivedQuotes.size}")
  19. //4th message
  20. quoteRepository!QuoteRepositoryRequest
  21. testProbe.expectTerminated(quoteRepository) //Expect a Terminated Message
  22. }
  23. }

2.如果没有观察(watched/unwatched)到则断言没收到Terminated消息

事实上,我们做这个只是演示下context.unwatch。如果我们移掉testProbe.watch和testProbe.unwatch这行,则测试case会运行的很正常。

  1. "not send back a termination message on 4th message if not watched" in {
  2. val quoteRepository=TestActorRef[QuoteRepositoryActor]
  3. val testProbe=TestProbe()
  4. testProbe.watch(quoteRepository) //watching
  5. within (1000 millis) {
  6. var receivedQuotes = List[String]()
  7. (1 to 3).foreach(_ => quoteRepository ! QuoteRepositoryRequest)
  8. receiveWhile() {
  9. case QuoteRepositoryResponse(quoteString) => {
  10. receivedQuotes = receivedQuotes :+ quoteString
  11. }
  12. }
  13. testProbe.unwatch(quoteRepository) //not watching anymore
  14. receivedQuotes.size must be (3)
  15. println(s"receiveCount ${receivedQuotes.size}")
  16. //4th message
  17. quoteRepository!QuoteRepositoryRequest
  18. testProbe.expectNoMsg() //Not Watching. No Terminated Message
  19. }
  20. }

3. 在TeacherActorWatcher中断言收到了Terminated消息

我们订阅了EventStream并通过检查一个特殊的日志消息来断言termination。

  1. "end back a termination message to the watcher on 4th message to the TeacherActor" in {
  2. //This just subscribes to the EventFilter for messages. We have asserted all that we need against the QuoteRepositoryActor in the previous testcase
  3. val teacherActor=TestActorRef[TeacherActorWatcher]
  4. within (1000 millis) {
  5. (1 to 3).foreach (_=>teacherActor!QuoteRequest) //this sends a message to the QuoteRepositoryActor
  6. EventFilter.error (pattern="""Child Actor .* Terminated""", occurrences = 1).intercept{
  7. teacherActor!QuoteRequest //Send the dangerous 4th message
  8. }
  9. }
  10. }

EventFilter中的pattern属性,没啥奇怪的,需要一个正则表达式。正则pattern="""Child Actor .* Terminated"""用来匹配一条格式是Child Actor {Actor[akka://TestUniversityMessageSystem/user/$$d/quoteRepositoryActor#-1905987636]} Terminated日志信息。

Github###

与往常一样,代码在github。看下deathwatch的包。


文章来自微信平台「麦芽面包」(微信扫描二维码关注)。未经允许,禁止转载。

[翻译]AKKA笔记 - DEATHWATCH -7的更多相关文章

  1. [翻译]AKKA笔记 -ACTOR SUPERVISION - 8

    失败更像是分布式系统的一个特性.因此Akka用一个容忍失败的模型,在你的业务逻辑与失败处理逻辑(supervision逻辑)中间你能有一个清晰的边界.只需要一点点工作,这很赞.这就是我们要讨论的主题. ...

  2. [翻译]AKKA笔记 - ACTOR生命周期 - 基本 -5

    原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/ (请注意这了讨论的生命周期并不包括 preRestart 或者pos ...

  3. [翻译] AKKA笔记- ACTORSYSTEM (配置CONFIGURATION 与调度SCHEDULING) - 4(一)

    原文在http://rerun.me/2014/10/06/akka-notes-actorsystem-in-progress/ 像我们前面看到的,我们可以用ActorSystem的actorof方 ...

  4. [翻译]AKKA笔记 - 有限状态机 -1

    原文地址:http://rerun.me/2016/05/21/akka-notes-finite-state-machines-1/ 我最近有个机会在工作上使用了Akka FSM,是个非常有趣的例子 ...

  5. [翻译]AKKA笔记 - CHILD ACTORS与ACTORPATH -6

    原文:http://rerun.me/2014/10/21/akka-notes-child-actors-and-path/ Actor是完全的继承结构.你创建的任何Actor肯定都是一个其他Act ...

  6. [翻译]AKKA笔记 - ACTOR MESSAGING - REQUEST AND RESPONSE -3

    上次我们看Actor消息机制,我们看到开火-忘记型消息发出(意思是我们只要发个消息给Actor但是不期望有响应). 技术上来讲, 我们发消息给Actors就是要它的副作用. 这就是这么设计的.除了不响 ...

  7. [翻译]AKKA笔记 - LOGGING与测试ACTORS -2 (二)

    3.THROW IN A LOGBACK.XML 现在我们把SLF4J日志配置在logback. <?xml version="1.0" encoding="UTF ...

  8. [翻译]AKKA笔记 - LOGGING与测试ACTORS -2 (一)

    在前两章 ( 一 , 二 ) ,我们大致讲了Actor和message是怎么工作的,让我们看一下日志和测试我们的 TeacherActor . RECAP 这是上一节我们的Actor代码: class ...

  9. 翻译:AKKA笔记 - Actor消息 -1(一)

    从第一篇Akka笔记的介绍中,我们是从很高的高度去观察Akka工具箱中的Actors.在这篇笔记的第二篇,我们会看一下Actors中的消息部分.而且延续上一次的例子,我们还会使用同样的学生与老师的例子 ...

随机推荐

  1. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  2. 一篇文章看懂TPCx-BB(大数据基准测试工具)源码

    TPCx-BB是大数据基准测试工具,它通过模拟零售商的30个应用场景,执行30个查询来衡量基于Hadoop的大数据系统的包括硬件和软件的性能.其中一些场景还用到了机器学习算法(聚类.线性回归等).为了 ...

  3. javascript单元测试框架mochajs详解

    关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...

  4. SQL Server2016升级前几点自检

    SQL Server2016已经出来一段时间了,而且最新的SP1包也于2016年11月18日正式发布,各种新的特性推出让我们跃跃欲试.那么对于我们真实的业务环境,特别是生产环境要不要"跟风& ...

  5. 在Windows上编译和调试CoreCLR

    生成CoreCLR - Windows篇 本文的唯一目的就是让你运行Hello World 运行环境 Window 7+ Visual studio 2015 确保C++ 工具已经被安装,默认是不安装 ...

  6. Asp.net Core准备工作

    1.安装环境 安装.Net Core SDK 安装VS2015 Update3 安装DotNetCore.1.0.1-VS2015Tools.Preview2.0.2.exe 2.新建Core工程 项 ...

  7. PHP获取客户端IP

    /** * 获取客户端IP */ function getClientIp() { $ip = 'unknown'; $unknown = 'unknown'; if (isset($_SERVER[ ...

  8. StringUtils的isBlank与isEmply

    1.public static boolean isEmpty(String str) 判断某字符串是否为空,为空的标准是 str==null 或 str.length()==0 StringUtil ...

  9. JAVA 分页工具类及其使用

    Pager.java package pers.kangxu.datautils.common; import java.io.Serializable; import java.util.List; ...

  10. System进程(pid=4)占用80端口的解决方案

    问题 Mail服务器在安装TFS服务(含SQLServer2016)后启动不了网页服务. 排查问题 使用命令查看端口占用情况 netstat -nao | find ":80" n ...