使用akka调度程序进行数据推送

时间:2016-09-27 15:52:39

标签: scala akka

我正在寻找关于akka调度程序用法的一些示例。我有一个actor(让我们调用它 - dataProducer)实现从一些数据库中检索数据。我想编写一个调度程序actor,它将在5秒的时间间隔内对dataProducer actor进行极化。如果数据检索比调度程序间隔花费更多时间,那么如何处理这种情况。调度程序actor中的scheduleOnce方法会处理这个吗?

这是我的调度程序演员

import java.util.concurrent.{Executors, TimeUnit}
import akka.actor.{Actor, Cancellable, Props}
import scala.concurrent.ExecutionContext

class SchedulerActor(interval: Long) extends Actor with LogF{

  implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(100))

  private var scheduler: Cancellable = _

  override def preStart(): Unit = {
    import scala.concurrent.duration._
    scheduler = context.system.scheduler.schedule(
      initialDelay = 0 seconds,
      interval = FiniteDuration(interval, TimeUnit.SECONDS),
      receiver = self,
      message = FetchData
    )
  }

  override def postStop(): Unit = {
    scheduler.cancel()
  }

  def receive = {
    case FetchData =>
      logger.debug( "Fetch Data" )
      sender() ! "Data Fetched!!!" //here I'll call dataProducer API
      true
    case unknown =>
      throw new RuntimeException( "ERROR: Received unknown message [" + unknown + "], can't handle it" )
  }

}

object SchedulerActor {

  def props(interval: Long): Props = Props(new SchedulerActor(interval))
}

sealed trait FetchDataMessage
case object FetchData extends FetchDataMessage

1 个答案:

答案 0 :(得分:0)

计划程序scheduleOnce有助于在延迟一段时间后执行。 具有不同的状态并在状态之间切换以接受不同类型的消息并相应地采取行动。但是当超时发生时,scheduleOnce会将你带到timeoutState。

ScheduleOnce将帮助演员知道超时已经发生。

  

如果数据检索比调度程序间隔花费更多时间,如何处理这种情况?

如果数据获取超过指定时间,则actor状态更改timeoutState并且在超时状态下说明应该对actor执行的操作。您可以重试或尝试不同的来源。

  

我想编写一个调度程序actor,它将在5秒间隔内使dataProducer actor处于极点

在结果状态中等待scheduleOnce,延迟时间为5秒,以请求dataProducer并重复整个事件。

检查此代码以了解如何完成。

import akka.actor.{Actor, Cancellable}
import stackoverflow.DBUtils.Entity

import scala.concurrent.Future
import scala.concurrent.duration._
import akka.pattern.pipe


object DBPollActor {
  case class Result(results: List[Entity])
  case object Schedule
  case object Timeup
  case object FetchData
}

object DBUtils {
  case class Entity(name: String)

  def doDBOperation: Future[List[Entity]] = {
    Future.successful(List(Entity(name = "foo")))
  }

}

class DBPollActor(timeout: Int) extends Actor {

  import DBPollActor._

  implicit val ex = context.system.dispatcher

  var schedulerOpt: Option[Cancellable] = None

  @scala.throws[Exception](classOf[Exception])
  override def preStart(): Unit = {
    super.preStart()
    self ! FetchData
    schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
      context become timeoutState
      self ! Timeup
    })
  }

  override def receive: Receive = {
    case msg@FetchData =>
      context become startState
      self forward msg
  }

  def startState: Receive = {
    case FetchData =>
      schedulerOpt.map(_.cancel())
      context become resultState
      DBUtils.doDBOperation.map(Result) pipeTo self
      schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
        context become timeoutState
        self ! Timeup
      })
  }

  def timeoutState: Receive = {
    case Timeup =>
      schedulerOpt.map(_.cancel())
      //Timeout happened do something or repeat
  }

  def resultState:  Receive = {
    case result@Result(list) =>
      schedulerOpt.map(_.cancel())
      //Result available consume the result and repeat or doSomething different
     context become resultState
      DBUtils.doDBOperation.map(Result) pipeTo self
      schedulerOpt = Some(context.system.scheduler.scheduleOnce(timeout seconds) {
        context become timeoutState
        self ! Timeup
      })

    case ex: Exception =>
      schedulerOpt.map(_.cancel())
      //future failed exit or retry
  }
}