五到七章先放一下,过段时间再看,akka还是比较给力的,最近忙着部署mesos和hive,过段时间也把部署和踩的一些小坑写一下,今天晚上换换脑子,做做akka的题
通过TimerActor类实现计时器,接收到含有超时设置变量t的Register消息后,该计时器应在过了变量t设置的时间后向发送Register消息的对象发回一条Timeout消息,该计时器必须能够接收多条Register消息
package com.linewell.chapter8
import akka.actor.{Props, ActorSystem, Actor}
import akka.actor.Actor.Receive
/** * Created by ctao on 15-12-13. */
object TimeOutTest extends App {
class TimeActor extends Actor {
override def receive: Receive = {
case Register(x) => if(x<=10000) {
Thread.sleep(x)
sender ! TimeOut(x)
} else{
sender ! Stop
}
case _ =>
}
}
class PrintTimerActor(receiverPath: String, outTime: Long) extends Actor {
override def receive: Actor.Receive = {
case Start => context.actorSelection(receiverPath) ! Register(outTime)
case TimeOut(x) => println(s"receive sender $sender message $x ms")
sender() ! Register(x + 1000)
case Stop => println("shutdown")
context.system.terminate()
}
}
val system = ActorSystem("timeout")
val timeActor = system.actorOf(Props[TimeActor], name = "time")
val printTimerActor = system.actorOf(Props(new PrintTimerActor("/user/time", 1000)))
printTimerActor ! Start
}
case class Register(t: Long)
case class TimeOut(time: Long)
case object Start
case object Stop
我的实现逻辑是定义一个Register样例类,一个超时样例类,其实这两个可以定义在一起,但为了区分职能这里还是分开定义,定义一个开始和一个结束的样例对象
printactor在接收到开始信号后就向指定路径的actor发送一个注册信号,timeoutactor在接收到注册信号后就会先休眠对应的时间,然后返回发送一个超时信息,printactor在收到超时信号后将打印超时信息,并再次向发送这个信号的actor发送一个注册信息,时间多了1s,当timeoutactor在接收大于10s的超时信号后则向发送者发送停止信号,printactor在接收到停止信号后将停止系统
账户在收到send指令后发送到指定账户指定金额,一旦交易没完成的时候收到kill指令则终止交易,这个问题我是用偏函数做的,但感觉还是过于复杂,而且后面指令的连续发送问题也会出现少量bug
package com.linewell.chapter8
import akka.actor.{Actor, ActorSystem, Props}
import akka.event.Logging
/** * Created by ctao on 2015/12/15. */
object Account extends App {
/** * 开始 */
case object Start
/** * 转账 * @param receiveActor 接收者 * @param sendMoney 金额 */
case class Sender(receiveActor: String, sendMoney: Double)
/** * 转账 * @param sendActor 发送者 * @param receiveMoney 金额 */
case class Receiver(sendActor: String, receiveMoney: Double)
/** * 结束 * @param i 多次握手 */
case class End(i: Int)
/** * 终止 */
case class Kill(i:Int)
/** * 账户actor * @param name 账户名 * @param money 金额 * @param otherAccount 交易账户 */
class AccountActor(name: String, var money: Double, otherAccount: String) extends Actor {
private val log = Logging(context.system, this)
/** * 内部的一个交易表 */
private val moneyBuffer = collection.mutable.ArrayBuffer[Double](0.0)
/** * 开始交易,如果收到Start信号则开始交易,将此时的状态设置为交易中,利用偏函数 */
def startTransAction: Receive = {
case Start => log.info("start transAction")
context.become(inTransAction)
}
/** * 进行交易 */
def inTransAction: Receive = {
/** * 发送指令 */
case Sender(receiveActor, sendMoney) =>
log.info(s"$name sender $sendMoney to $receiveActor")
/** * 内部表维护一个减少的金额 */
moneyBuffer += -sendMoney
/** * 给交易账户发送一个接收指令 */
context.actorSelection(otherAccount) ! Receiver(self.path.toString, sendMoney)
/** * 接收指令 */
case Receiver(senderActor, receiveMoney) =>
log.info(s"$name receive $receiveMoney from $senderActor")
/** * 内部表加入接收金额 */
moneyBuffer += receiveMoney
/** * 终止交易 */
case Kill(0) => log.info("kill transaction")
context.become(killTransAction)
self ! Kill(1)
/** * 结束指令,如果是在交易时收到结束指令,且状态为0,则将偏函数设置为结束交易,并向自己发送一个结束信号 */
case End(0) => log.info(s"end transAction $name")
context.become(endTransAction)
self ! End(1)
}
/** * 必须在结束偏函数中收到指令为1的才能结束交易,而收到这个指令始终为自己发送的 */
def endTransAction: Receive = {
case End(1) =>
money += moneyBuffer.sum
log.info(s"name $name money $money")
moneyBuffer.clear()
context.actorSelection(otherAccount) ! End(0)
context.become(startTransAction)
}
/** *在kill指令收到后将清空链表,这个指令始终为自己发送 */
def killTransAction:Receive = {
case Kill(1) =>
moneyBuffer.clear()
log.info(s"name $name money $money")
context.actorSelection(otherAccount) ! Kill(0)
context.become(startTransAction)
}
override def receive: Actor.Receive = startTransAction
override def unhandled(msg: Any) = {
log.info(s"cannot handle message $msg in this state.")
}
}
val system = ActorSystem("account")
val a = system.actorOf(Props(new AccountActor("a", 1000,"/user/b")), name = "a")
val b = system.actorOf(Props(new AccountActor("b", 1000,"/user/a")), name = "b")
b ! Start
a ! Start
for (i <- 1 to 10) {
a ! Sender("/user/b", i)
}
b ! Kill(0)
Thread sleep 1000
a ! End(0)
a ! Start
b ! Start
for (i <- 1 to 10) {
a ! Sender("/user/b", i)
}
a ! Kill(0)
Thread sleep 1000
system.terminate()
}
实现SessionActor类,使用SessionActor对象控制其他对象的Actor对象的访问操作,
SessionActor实例在接收到含有正确密码的StartSession消息后,应该将所有消息转发给Actor对象r,直到他收到EndSession消息为止
package com.linewell.chapter8
import akka.actor.Actor.Receive
import akka.actor.{ActorSystem, Props, Actor, ActorRef}
/** * Created by ctao on 15-12-14. */
object SessionActorTest extends App {
case class Message(msg: String)
case class StartSession(pass: String)
case object EndSession
class SessionActor(password: String, r: ActorRef) extends Actor {
private var check = false
override def receive: Receive = {
case StartSession(pass) => if (pass == password) {
check = true
println("Success start session")
} else println("Error pass")
case Message(msg) => if (check) r ! Message(msg) else println("Please check password before send message")
case EndSession => check = false
println("End Session")
case _ => println("ingore")
}
}
class PrintActor extends Actor {
override def receive: Actor.Receive = {
case Message(msg) => println(s"receive from $sender : message $msg")
case _ =>
}
}
object SessionActor {
def apply(password: String, actorRef: ActorRef) = Props(new SessionActor(password, actorRef))
}
val system = ActorSystem("session")
val printActor = system.actorOf(Props[PrintActor], name = "print")
val sessionActor = system.actorOf(SessionActor("ctao", printActor))
sessionActor ! StartSession("cc")
sessionActor ! StartSession("ctao")
for (i <- 1 to 10) sessionActor ! Message(s"the num is $i")
sessionActor ! EndSession
sessionActor ! Message("check test")
system.terminate()
}
思想,消息分为三种,一种是校验password的消息,StartSeesion,一种是结束session生命周期的EndSession,一种是真正的消息,转发给其他actor的,
actor有两种,一种是seesionActor,一种是printActor,sessionActor内部维护一个校验标志,如果接收到StartSession而且密码正确则完成校验,设置校验标志为真,否则提示重新校验,如果收到普通消息,且校验标志为真,则完成转发,否则则提示进行校验,如果收到结束session标志,则将校验标注设置为false
printActor则完成打印