当我们说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把自己杀掉

这没啥神奇的。

package me.rerun.akkanotes.deathwatch

import akka.actor.{PoisonPill, Actor, ActorLogging, actorRef2Scala}
import me.rerun.akkanotes.protocols.QuoteRepositoryProtocol._
import scala.util.Random class QuoteRepositoryActor() extends Actor with ActorLogging { val quotes = List(
"Moderation is for cowards",
"Anything worth doing is worth overdoing",
"The trouble is you think you have time",
"You never gonna know if you never even try") var repoRequestCount:Int=1 def receive = { case QuoteRepositoryRequest => { if (repoRequestCount>3){
self!PoisonPill
}
else {
//Get a random Quote from the list and construct a response
val quoteResponse = QuoteRepositoryResponse(quotes(Random.nextInt(quotes.size))) log.info(s"QuoteRequest received in QuoteRepositoryActor. Sending response to Teacher Actor $quoteResponse")
repoRequestCount=repoRequestCount+1
sender ! quoteResponse
} } } }

TEACHERACTORWATCHER

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

package me.rerun.akkanotes.deathwatch

import akka.actor.{Terminated, Props, Actor, ActorLogging}
import me.rerun.akkanotes.protocols.TeacherProtocol.QuoteRequest
import me.rerun.akkanotes.protocols.QuoteRepositoryProtocol.QuoteRepositoryRequest class TeacherActorWatcher extends Actor with ActorLogging { val quoteRepositoryActor=context.actorOf(Props[QuoteRepositoryActor], "quoteRepositoryActor")
context.watch(quoteRepositoryActor) def receive = {
case QuoteRequest => {
quoteRepositoryActor ! QuoteRepositoryRequest
}
case Terminated(terminatedActorRef)=>{
log.error(s"Child Actor {$terminatedActorRef} Terminated")
}
}
}

测试CASE

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

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

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

"A QuoteRepositoryActor" must {
...
...
... "send back a termination message to the watcher on 4th message" in {
val quoteRepository=TestActorRef[QuoteRepositoryActor] val testProbe=TestProbe()
testProbe.watch(quoteRepository) //Let's watch the Actor within (1000 millis) {
var receivedQuotes = List[String]()
(1 to 3).foreach(_ => quoteRepository ! QuoteRepositoryRequest)
receiveWhile() {
case QuoteRepositoryResponse(quoteString) => {
receivedQuotes = receivedQuotes :+ quoteString
}
} receivedQuotes.size must be (3)
println(s"receiveCount ${receivedQuotes.size}") //4th message
quoteRepository!QuoteRepositoryRequest
testProbe.expectTerminated(quoteRepository) //Expect a Terminated Message
}
}

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

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

    "not send back a termination message on 4th message if not watched" in {
val quoteRepository=TestActorRef[QuoteRepositoryActor] val testProbe=TestProbe()
testProbe.watch(quoteRepository) //watching within (1000 millis) {
var receivedQuotes = List[String]()
(1 to 3).foreach(_ => quoteRepository ! QuoteRepositoryRequest)
receiveWhile() {
case QuoteRepositoryResponse(quoteString) => {
receivedQuotes = receivedQuotes :+ quoteString
}
} testProbe.unwatch(quoteRepository) //not watching anymore
receivedQuotes.size must be (3)
println(s"receiveCount ${receivedQuotes.size}") //4th message
quoteRepository!QuoteRepositoryRequest
testProbe.expectNoMsg() //Not Watching. No Terminated Message
}
}

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

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

   "end back a termination message to the watcher on 4th message to the TeacherActor" in {

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

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. [linux]阿里云主机的免登陆安全SSH配置与思考

    公司服务器使用的第三方云端服务,即阿里云,而本地需要经常去登录到服务器做相应的配置工作,鉴于此,每次登录都要使用密码是比较烦躁的,本着极速思想,我们需要配置我们的免登陆. 一 理论概述 SSH介绍 S ...

  2. 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车

     阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...

  3. C++中的变长参数

    新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数.在需要的地方调用自定义的MemNew函数.这样就带来一个问题,使用stl的 ...

  4. 6.DNS公司PC访问外网的设置 + 主DNS服务器和辅助DNS服务器的配置

    网站部署之~Windows Server | 本地部署 http://www.cnblogs.com/dunitian/p/4822808.html#iis DNS服务器部署不清楚的可以看上一篇:ht ...

  5. .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来

    从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ...

  6. OVS 中的各种网络设备 - 每天5分钟玩转 OpenStack(128)

    上一节我们启用了 Open vSwitch,本节将查看当前的网络状态并介绍 Open vSwitch 涉及的各种网络设备 初始网络状态 查看一下当前的网络状态. 控制节点 ifconfig 显示控制节 ...

  7. .net Elasticsearch 学习入门笔记

    一. es安装相关1.elasticsearch安装  运行http://localhost:9200/2.head插件3.bigdesk插件安装(安装细节百度:windows elasticsear ...

  8. [C#] 简单的 Helper 封装 -- SecurityHelper 安全助手:封装加密算法(MD5、SHA、HMAC、DES、RSA)

    using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Wen. ...

  9. javascript表单的Ajax 提交插件的使用

    Ajax 提交插件 form.js 表单的下载地址:官方网站:http://malsup.com/jquery/form/ form.js 插件有两个核心方法:ajaxForm()和ajaxSubmi ...

  10. LoadRunner函数百科叒叒叒更新了!

    首先要沉痛通知每周四固定栏目[学霸君]由于小编外派公干,本周暂停. 那么这周就由云层君来顶替了,当然要要说下自己做的内容啦,DuangDuang! <LoadRunner函数百科>更新通知 ...