• [翻译]AKKA笔记


    上次我们看Actor消息机制,我们看到开火-忘记型消息发出(意思是我们只要发个消息给Actor但是不期望有响应)。

    技术上来讲, 我们发消息给Actors就是要它的副作用。 这就是这么设计的。除了不响应, 目标Actor当然也可以对消息做以下事情-

    1.发送一个响应给发送者(在我们的case里,TeacherActor应该响应一首名言给StudentActor

    2.转发一个响应给其他的潜在的受众Actor,他们也可能响应/转发/产生副作用。Routers(路由)和Supervisors(监管)就是这个例子。(我们马上就能看到)


    REQUEST & RESPONSE
    这次,我们只关注第一点- 请求-响应的周期。

    图片说明了我们这次在尝试归档做什么。为了简介,我没有在图中加入ActorSystem, Dispathcer或Mailboxes。

    1. DriverApp发送一个InitSignal(初始化信号)消息给StudentActor.

    2. StudentActor反馈给InitSignal消息并且发送一条QuoteRequest(格言请求)消息给TeacherActor

    3. TeacherActor,像我们在第一次看到的,响应一条QuoteResponse

    4. StudentActor只记录QuoteResponse(格言响应)到控制台/日志记录器。

    我们可以写个testcase来验证。

    让我们看下这4点的细节:

    1. DRIVERAPP发送一个INITSIGNAL消息给STUDENTACTOR

    至此,你可能已经猜出DriverApp会做什么。 就4件事:

    1) 初始化ActorSystem

    //Initialize the ActorSystem
      val system = ActorSystem("UniversityMessageSystem")
    
    1. 创建TeacherActor
    //create the teacher actor
      val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
    
    1. 创建StudentActor
    //create the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
      val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
    

    你可以看到我把ActorRef的实例TeacherActorStudentActor的构造函数,这样StudentActor可以使用ActorRef发消息给TeacherActor。还有另外的方式达到这个目的(如传入Props),但是这个方法对我们后面看到的Supervisors和Routers会方便点。我们也会即将看到child actors但现在还不是一个好方式 - Student创建Teacher听起来怪怪的吧?

    最后,

    4) DriverApp会发一个InitSignalStudentActor, z何阳StudentActor就能开始发送QuoteRequest(格言请求)给TeacherActor。

    //send a message to the Student Actor
      studentRef ! InitSignal
    

    这个DriverClass讲差不多了。 Thread.sleepActorSystem.shutdown在我们最后关闭ActorSystem的时候会在发消息时会等待几秒保证结束。

    ** DRIVERAPP.SCALA**

    package me.rerun.akkanotes.messaging.requestresponse
    
    import akka.actor.ActorSystem  
    import akka.actor.Props  
    import me.rerun.akkanotes.messaging.protocols.StudentProtocol._  
    import akka.actor.ActorRef
    
    object DriverApp extends App {
    
      //Initialize the ActorSystem
      val system = ActorSystem("UniversityMessageSystem")
    
      //construct the teacher actor
      val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
    
      //construct the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
      val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
    
      //send a message to the Student Actor
      studentRef ! InitSignal
    
      //Let's wait for a couple of seconds before we shut down the system
      Thread.sleep(2000)
    
      //Shut down the ActorSystem. 
      system.shutdown()
    
    }
    

    2. STUDENTACTOR响应给INITSIGNAL消息并且发送一条QUOTEREQUEST消息给TEACHERACTOR###

    以及

    4. STUDENTACTORTEACHERACTOR接收到QUOTERESPONSE并且将日志记录到控制台/日志记录器###

    为什么我把2和4条绑在一起?因为实在太简单了,要是拆开来你要恨死我。

    所以,第二点 - StudentActor从DriverApp接到InitSignal消息并且发送QuoteRequest给TeacherActor。

    def receive = {  
        case InitSignal=> {
              teacherActorRef!QuoteRequest
        }
        ...
        ...
    

    就这么多!

    第四点 - StudentActor记录从TeacherActor发来的日志消息。

    就像我们承诺的:

    case QuoteResponse(quoteString) => {  
          log.info ("Received QuoteResponse from Teacher")
          log.info(s"Printing from Student Actor $quoteString")
    }
    

    我想你肯定同意现在这个看起来跟伪代码一样。

    所以整个的StudentActor类看起来就是这样:

    STUDENTACTOR.SCALA###

    package me.rerun.akkanotes.messaging.requestresponse
    
    import akka.actor.Actor  
    import akka.actor.ActorLogging  
    import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._  
    import me.rerun.akkanotes.messaging.protocols.StudentProtocol._  
    import akka.actor.Props  
    import akka.actor.ActorRef
    
    class StudentActor (teacherActorRef:ActorRef) extends Actor with ActorLogging {
    
      def receive = {
        case InitSignal=> {
          teacherActorRef!QuoteRequest
        }
    
        case QuoteResponse(quoteString) => {
          log.info ("Received QuoteResponse from Teacher")
          log.info(s"Printing from Student Actor $quoteString")
        }
      }
    }
    

    3. TEACHERACTOR响应QUOTERESPONSE消息###

    这就跟我们在fire-n-forget 那里写的代码差不多。

    TeacherActor接受一条QuoteRequest消息并且返回一条QuoteResponse

    TEACHERACTOR.SCALA###

    package me.rerun.akkanotes.messaging.requestresponse
    
    import scala.util.Random
    
    import akka.actor.Actor  
    import akka.actor.ActorLogging  
    import akka.actor.actorRef2Scala  
    import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._
    
    
    class TeacherActor 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")
    
      def receive = {
    
        case QuoteRequest => {
    
          import util.Random
    
          //Get a random Quote from the list and construct a response
          val quoteResponse = QuoteResponse(quotes(Random.nextInt(quotes.size)))
    
          //respond back to the Student who is the original sender of QuoteRequest
          sender ! quoteResponse
    
        }
      }
    }
    

    测试用例TESTCASES###

    现在,我们的测试用例会模拟DriverApp。由于StudentActor只是记录消息,我们无法对QuoteResponse消息进行断言,我们只断言消息在EventStream里出现(就像我们之前
    说的)

    所以,我们的测试用例就像这样:

    "A student" must {
    
        "log a QuoteResponse eventually when an InitSignal is sent to it" in {
    
          import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
    
          val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
          val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
    
          EventFilter.info (start="Printing from Student Actor", occurrences=1).intercept{
            studentRef!InitSignal
          }
        }
      }
    

    源码###

    整个工程可以在github下载。

    下一步,我们会看到怎样使用Akka的schedulers并且用Kamon监控你的Akka应用。


    文章来自微信平台「麦芽面包」,微信号「darkjune_think」。转载请注明。

  • 相关阅读:
    python基础-枚举定义错误码
    凸包-Graham扫描法
    [USACO04OPEN]MooFest
    [USACO16OPEN]262144
    [ASPNETCORE] 抛砖引玉,EFCORE 软删除和自动添加审计的实现
    java 文件读取汇总
    java 各类型转换 convert
    java 各类型初始化汇总
    java 常用类型占用字节数
    Maven 常用命令
  • 原文地址:https://www.cnblogs.com/zhukunrong/p/4960679.html
Copyright © 2020-2023  润新知