心跳消息的方式

时间:2014-08-19 15:59:23

标签: scala akka heartbeat

我正在尝试通过网络设置心跳,即让演员在固定的时间段内向网络发送消息。我想知道你是否有比我下面使用的更好的解决方案,因为我觉得非常难看,考虑到同步限制。

import akka.actor._
import akka.actor.Actor
import akka.actor.Props
import akka.actor.ScalaActorRef
import akka.pattern.gracefulStop
import akka.util._
import java.util.Calendar
import java.util.concurrent._
import java.text.SimpleDateFormat
import scala.Array._
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

sealed trait Message
case class Information() extends Message//does really need to be here?
case class StartMessage() extends Message
case class HeartbeatMessage() extends Message
case class StopMessage() extends Message
case class FrequencyChangeMessage(
    f: Int
) extends Message

class Gps extends Actor {
    override def preStart() {
        val child = context.actorOf(Props(new Cadencer(500)), name = "cadencer")
    }
    def receive = {
        case "beat" =>
            //TODO
        case _      =>
            println("gps: wut?")
    }
}

class Cadencer(p3riod: Int) extends Actor {
    var period: Int = _
    var stop: Boolean = _
    override def preStart() {
        period = p3riod
        stop = false
        context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
    }
    def receive = {
        case StartMessage =>
            stop = false
            context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
        case HeartbeatMessage =>
            if (false == stop) {
                context.system.scheduler.scheduleOnce(0 milliseconds, context.parent, "beat")
                context.system.scheduler.scheduleOnce(period milliseconds, self, HeartbeatMessage)
            }
        case StopMessage =>
            stop = true
        case FrequencyChangeMessage(f) =>
            period = f
        case _  =>
            println("wut?\n")
            //throw exception
    }
}

object main extends App {
    val system = akka.actor.ActorSystem("mySystem")
    val gps = system.actorOf(Props[Gps], name = "gps")
}

我在此处调用的cadencer会向目标actor发送一个HeartbeatMessage;在给定的时间之后发送订单以重新发送一个订单,从而继续进行StopMessage(将stop翻转到true)。好?

是否有一个独立的actor效率而不是更大的一个?

2 个答案:

答案 0 :(得分:1)

试试这个。它不需要单独的cadencer类。

class Gps extends Actor
{
  var ticker : Cancellable = _

  override def preStart()
  {
    println ("Gps prestart")
    // val child = context.actorOf(Props(new Cadencer(500)), name = "cadencer")
    ticker = context.system.scheduler.schedule (
      500 milliseconds,
      500 milliseconds,
      context.self,
      "beat")
  }

  def receive: PartialFunction[Any, Unit] =
  {
    case "beat" =>
      println ("got a beat")

    case "stop" =>
      ticker.cancel()

    case _ =>
      println("gps: wut?")
  }
}

object main extends App
{
  val system = akka.actor.ActorSystem("mySystem")
  val gps = system.actorOf(Props[Gps], name = "gps")

  Thread.sleep (5000)
  gps ! "stop"
  println ("stop")
}

答案 1 :(得分:0)

演员非常轻量级,所以让一个演员发送心跳消息是没有问题的(如果你想到单一责任原则,它更可取。)

进一步评论:

如果你想摆脱期间变量,你可以做以下事情(它被称为hotswapping):

override def preStart() {
  // ...
  context.become(receive(p3riod))   
}

def receive(period: Int) = {
  // ...
  case FrequencyChangeMessage(f) =>
    context.become(receive(f))
  // ...
}

您可以在获取StopMessage后停止actor,而不是使用stop var。 如果你再次需要一个心跳演员,那就开始一个新的。

您可以将消息直接发送给父级,而不是使用0毫秒进行调度。