akka.actor.ReceiveTimeout Scala Examples

The following examples show how to use akka.actor.ReceiveTimeout. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: IngestionHandler.scala    From hydra   with Apache License 2.0 5 votes vote down vote up
package hydra.ingest.services

import akka.actor.SupervisorStrategy.Stop
import akka.actor.{Actor, ActorRef, OneForOneStrategy, ReceiveTimeout}
import akka.http.scaladsl.model.{StatusCode, StatusCodes}
import hydra.core.ingest.{HydraRequest, IngestionReport, RequestParams}
import hydra.ingest.services.IngestorRegistry.{
  FindAll,
  FindByName,
  LookupResult
}

import scala.concurrent.duration.FiniteDuration

trait IngestionHandler {
  this: Actor =>

  def timeout: FiniteDuration

  def request: HydraRequest

  //we require an actorref here for performance reasons
  def registry: ActorRef

  private val targetIngestor =
    request.metadataValue(RequestParams.HYDRA_INGESTOR_PARAM)

  targetIngestor match {
    case Some(ingestor) => registry ! FindByName(ingestor)
    case None           => registry ! FindAll
  }

  override def receive: Receive = {
    case LookupResult(Nil) =>
      val errorCode = targetIngestor
        .map(i =>
          StatusCodes
            .custom(404, s"No ingestor named $i was found in the registry.")
        )
        .getOrElse(StatusCodes.BadRequest)

      complete(errorWith(errorCode))

    case LookupResult(ingestors) =>
      context.actorOf(
        IngestionSupervisor.props(request, self, ingestors, timeout)
      )

    case report: IngestionReport =>
      complete(report)

  }

  override val supervisorStrategy =
    OneForOneStrategy() {
      case e: Exception =>
        fail(e)
        Stop
    }

  private def errorWith(statusCode: StatusCode) = {
    IngestionReport(request.correlationId, Map.empty, statusCode.intValue())
  }

  def complete(report: IngestionReport)

  def fail(e: Throwable)
} 
Example 2
Source File: InitializingActor.scala    From hydra   with Apache License 2.0 5 votes vote down vote up
package hydra.core.akka

import akka.actor.{Actor, ActorRef, ReceiveTimeout, Stash}
import akka.pattern.pipe
import hydra.common.config.ActorConfigSupport
import hydra.common.logging.LoggingAdapter
import hydra.core.HydraException
import hydra.core.akka.InitializingActor.{InitializationError, Initialized}
import hydra.core.protocol.HydraMessage
import retry.Success

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.control.NonFatal

trait InitializingActor
    extends Actor
    with ActorConfigSupport
    with Stash
    with LoggingAdapter {

  
  def initializationError(ex: Throwable): Receive
}

object InitializingActor {

  case object Initialized extends HydraMessage

  case class InitializationError(cause: Throwable) extends HydraMessage

}

@SerialVersionUID(1L)
class ActorInitializationException(
    ingestor: ActorRef,
    message: String,
    cause: Throwable
) extends HydraException(
      ActorInitializationException.enrichedMessage(ingestor, message),
      cause
    ) {
  def getActor: ActorRef = ingestor
}

object ActorInitializationException {

  private def enrichedMessage(actor: ActorRef, message: String) =
    Option(actor).map(a => s"${a.path}: $message").getOrElse(message)

  private[hydra] def apply(
      actor: ActorRef,
      message: String,
      cause: Throwable = null
  ) =
    new ActorInitializationException(actor, message, cause)

  def unapply(
      ex: ActorInitializationException
  ): Option[(ActorRef, String, Throwable)] =
    Some((ex.getActor, ex.getMessage, ex.getCause))
} 
Example 3
Source File: SocialMediaStalker.scala    From Akka-Cookbook   with MIT License 5 votes vote down vote up
package com.packt.chapter10

import akka.actor.{Actor, ActorLogging, ActorRef, ReceiveTimeout}
import com.packt.chapter10.SocialMediaAggregator.{Report, StartFetching, StopFetching}

import scala.collection.mutable
import scala.concurrent.duration._

class SocialMediaStalker(aggregator: ActorRef, userId: String) extends Actor with ActorLogging {
  import context.dispatcher

  context.setReceiveTimeout(10 seconds)

  val counts = mutable.Map.empty[String, Int].withDefaultValue(0)

  override def preStart() = {
    log.info("Politely asking to aggregate")
    aggregator ! StartFetching(userId, 1 second)
    context.system.scheduler.scheduleOnce(5 second, aggregator, StopFetching(userId))
  }

  override def postStop() = {
    log.info(s"Stopping. Overall counts for $userId: $counts")
  }

  def receive = {
    case Report(list) =>
      val stats = list.groupBy(_.socialNetwork).mapValues(_.map(_.posts.size).sum)
      log.info(s"New report: $stats")
      stats.foreach(kv => counts += kv._1 -> (counts(kv._1) + kv._2))
    case ReceiveTimeout =>
      context.stop(self)
  }
} 
Example 4
Source File: WebsocketSession.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.websockets

import java.util.concurrent.TimeUnit

import akka.actor.{Actor, ActorRef, PoisonPill, Props, ReceiveTimeout, Stash, Terminated}
import cool.graph.akkautil.{LogUnhandled, LogUnhandledExceptions}
import cool.graph.bugsnag.BugSnagger
import cool.graph.messagebus.QueuePublisher
import cool.graph.websockets.protocol.Request
import scala.collection.mutable
import scala.concurrent.duration._ // if you don't supply your own Protocol (see below)

object WebsocketSessionManager {
  object Requests {
    case class OpenWebsocketSession(projectId: String, sessionId: String, outgoing: ActorRef)
    case class CloseWebsocketSession(sessionId: String)

    case class IncomingWebsocketMessage(projectId: String, sessionId: String, body: String)
    case class IncomingQueueMessage(sessionId: String, body: String)
  }

  object Responses {
    case class OutgoingMessage(text: String)
  }
}

case class WebsocketSessionManager(
    requestsPublisher: QueuePublisher[Request],
    bugsnag: BugSnagger
) extends Actor
    with LogUnhandled
    with LogUnhandledExceptions {
  import WebsocketSessionManager.Requests._

  val websocketSessions = mutable.Map.empty[String, ActorRef]

  override def receive: Receive = logUnhandled {
    case OpenWebsocketSession(projectId, sessionId, outgoing) =>
      val ref = context.actorOf(Props(WebsocketSession(projectId, sessionId, outgoing, requestsPublisher, bugsnag)))
      context.watch(ref)
      websocketSessions += sessionId -> ref

    case CloseWebsocketSession(sessionId) =>
      websocketSessions.get(sessionId).foreach(context.stop)

    case req: IncomingWebsocketMessage =>
      websocketSessions.get(req.sessionId) match {
        case Some(session) => session ! req
        case None =>
          println(s"No session actor found for ${req.sessionId} | ${req.projectId} when processing websocket message. This should only happen very rarely.")
      }

    case req: IncomingQueueMessage =>
      websocketSessions.get(req.sessionId) match {
        case Some(session) => session ! req
        case None          => // Session already closed
      }

    case Terminated(terminatedActor) =>
      websocketSessions.retain {
        case (_, sessionActor) => sessionActor != terminatedActor
      }
  }
}

case class WebsocketSession(
    projectId: String,
    sessionId: String,
    outgoing: ActorRef,
    requestsPublisher: QueuePublisher[Request],
    bugsnag: BugSnagger
) extends Actor
    with LogUnhandled
    with LogUnhandledExceptions
    with Stash {
  import WebsocketSessionManager.Requests._
  import WebsocketSessionManager.Responses._
  import metrics.SubscriptionWebsocketMetrics._

  activeWsConnections.inc
  context.setReceiveTimeout(FiniteDuration(60, TimeUnit.MINUTES))

  def receive: Receive = logUnhandled {
    case IncomingWebsocketMessage(_, _, body) => requestsPublisher.publish(Request(sessionId, projectId, body))
    case IncomingQueueMessage(_, body)        => outgoing ! OutgoingMessage(body)
    case ReceiveTimeout                       => context.stop(self)
  }

  override def postStop = {
    activeWsConnections.dec
    outgoing ! PoisonPill
    requestsPublisher.publish(Request(sessionId, projectId, "STOP"))
  }
} 
Example 5
Source File: ClusterShardingQuickTerminationSpec.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.sharding

import akka.actor.{ ActorLogging, ActorRef, Props, ReceiveTimeout }
import akka.cluster.{ Cluster, MemberStatus }
import akka.cluster.sharding.{ ClusterSharding, ClusterShardingSettings, ShardRegion }
import akka.persistence.PersistentActor
import akka.persistence.cassandra.CassandraSpec
import akka.testkit.TestProbe

import scala.concurrent.duration._

object ClusterShardingQuickTerminationSpec {

  case object Increment
  case object Decrement
  final case class Get(counterId: Long)
  final case class EntityEnvelope(id: Long, payload: Any)
  case object Ack

  case object Stop
  final case class CounterChanged(delta: Int)

  class Counter extends PersistentActor with ActorLogging {
    import ShardRegion.Passivate

    context.setReceiveTimeout(5.seconds)

    // self.path.name is the entity identifier (utf-8 URL-encoded)
    override def persistenceId: String = "Counter-" + self.path.name

    var count = 0

    def updateState(event: CounterChanged): Unit =
      count += event.delta

    override def receiveRecover: Receive = {
      case evt: CounterChanged => updateState(evt)
      case other               => log.debug("Other: {}", other)
    }

    override def receiveCommand: Receive = {
      case Increment      => persist(CounterChanged(+1))(updateState)
      case Decrement      => persist(CounterChanged(-1))(updateState)
      case Get(_)         => sender() ! count
      case ReceiveTimeout => context.parent ! Passivate(stopMessage = Stop)
      case Stop =>
        sender() ! Ack
        context.stop(self)
    }
  }
  val extractEntityId: ShardRegion.ExtractEntityId = {
    case EntityEnvelope(id, payload) => (id.toString, payload)
    case msg @ Get(id)               => (id.toString, msg)
  }

  val numberOfShards = 100

  val extractShardId: ShardRegion.ExtractShardId = {
    case EntityEnvelope(id, _) => (id % numberOfShards).toString
    case Get(id)               => (id % numberOfShards).toString
  }

}

class ClusterShardingQuickTerminationSpec extends CassandraSpec("""
    akka.actor.provider = cluster
  """.stripMargin) {

  import ClusterShardingQuickTerminationSpec._

  "Cassandra Plugin with Cluster Sharding" must {
    "clear state if persistent actor shuts down" in {
      Cluster(system).join(Cluster(system).selfMember.address)
      awaitAssert {
        Cluster(system).selfMember.status shouldEqual MemberStatus.Up
      }
      ClusterSharding(system).start(
        typeName = "tagging",
        entityProps = Props[Counter],
        settings = ClusterShardingSettings(system),
        extractEntityId = extractEntityId,
        extractShardId = extractShardId)

      (0 to 100).foreach { i =>
        val counterRegion: ActorRef = ClusterSharding(system).shardRegion("tagging")
        awaitAssert {
          val sender = TestProbe()
          counterRegion.tell(Get(123), sender.ref)
          sender.expectMsg(500.millis, i)
        }

        counterRegion ! EntityEnvelope(123, Increment)
        counterRegion ! Get(123)
        expectMsg(i + 1)

        counterRegion ! EntityEnvelope(123, Stop)
        expectMsg(Ack)
      }
    }
  }
} 
Example 6
Source File: Passivation.scala    From akka-dddd-template   with Apache License 2.0 5 votes vote down vote up
package com.boldradius.cqrs

import akka.actor.{PoisonPill, Actor, ReceiveTimeout}
import com.boldradius.util.ALogging
import akka.contrib.pattern.ShardRegion.Passivate

trait Passivation extends ALogging {
  this: Actor =>

  protected def passivate(receive: Receive): Receive = receive.orElse{
    // tell parent actor to send us a poisinpill
    case ReceiveTimeout =>
      self.logInfo( s => s" $s ReceiveTimeout: passivating. ")
      context.parent ! Passivate(stopMessage = PoisonPill)

    // stop
    case PoisonPill => context.stop(self.logInfo( s => s" $s PoisonPill"))
  }
} 
Example 7
Source File: ProcessManager.scala    From akka-cqrs   with Apache License 2.0 5 votes vote down vote up
package com.productfoundry.akka.cqrs.process

import akka.actor.{ActorLogging, ReceiveTimeout}
import akka.persistence.fsm.PersistentFSM
import akka.persistence.fsm.PersistentFSM.FSMState
import akka.productfoundry.contrib.pattern.ReceivePipeline
import com.productfoundry.akka.cqrs.Entity
import com.productfoundry.akka.cqrs.publish.EventPublicationInterceptor


trait FsmProcessManager[S <: FSMState, D, E <: ProcessManagerEvent]
  extends ProcessManager
  with PersistentFSM[S, D, E]
  with ReceivePipeline
  with EventPublicationInterceptor {

  def passivationStateFunction: StateFunction = {
    case Event(ReceiveTimeout, _) => stop()
  }

  whenUnhandled(passivationStateFunction)
} 
Example 8
Source File: GracefulPassivation.scala    From akka-cqrs   with Apache License 2.0 5 votes vote down vote up
package com.productfoundry.akka

import akka.actor.{Actor, ReceiveTimeout}

import scala.concurrent.duration._


  override def unhandled(message: Any): Unit = {
    message match {
      case ReceiveTimeout => requestPassivation()
      case msg if msg == passivationConfig.passivationMessage => context.stop(self)
      case _ => super.unhandled(message)
    }
  }

  def requestPassivation(): Unit = {
    context.parent ! PassivationRequest(passivationConfig.passivationMessage)
  }
} 
Example 9
Source File: Worker.scala    From akka-iot-mqtt-v2   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package akkaiot

import java.util.UUID
import scala.concurrent.duration._
import akka.actor.{ Props, ActorRef, Actor, ActorLogging, ReceiveTimeout, Terminated }
import akka.cluster.client.ClusterClient.SendToAll
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.Stop
import akka.actor.SupervisorStrategy.Restart
import akka.actor.ActorInitializationException
import akka.actor.DeathPactException

object Worker {

  def props(clusterClient: ActorRef, workProcessorProps: Props, registerInterval: FiniteDuration = 10.seconds): Props =
    Props(classOf[Worker], clusterClient, workProcessorProps, registerInterval)

  case class WorkProcessed(result: WorkResult)
}

class Worker(clusterClient: ActorRef, workProcessorProps: Props, registerInterval: FiniteDuration)
  extends Actor with ActorLogging {
  import Worker._
  import MasterWorkerProtocol._

  val workerId = UUID.randomUUID().toString

  import context.dispatcher
  val registerTask = context.system.scheduler.schedule(0.seconds, registerInterval, clusterClient,
    SendToAll("/user/master/singleton", RegisterWorker(workerId)))

  val workProcessor = context.watch(context.actorOf(workProcessorProps, "work-processor"))

  var currentWorkId: Option[String] = None
  def workId: String = currentWorkId match {
    case Some(workId) => workId
    case None => throw new IllegalStateException("Not working")
  }

  override def supervisorStrategy = OneForOneStrategy() {
    case _: ActorInitializationException => Stop
    case _: DeathPactException => Stop
    case _: Exception =>
      currentWorkId foreach { workId => sendToMaster(WorkFailed(workerId, workId)) }
      context.become(idle)
      Restart
  }

  override def postStop(): Unit = registerTask.cancel()

  def receive = idle

  def idle: Receive = {
    case WorkIsReady =>
      sendToMaster(WorkerRequestsWork(workerId))

    case work @ Work(workId, deviceType, deviceId, state, setting) =>
      log.info("Worker -> Received work request from {}-{} | State {} | Setting {}", deviceType, deviceId, state, setting)
      currentWorkId = Some(workId)
      workProcessor ! work
      context.become(working)
  }

  def working: Receive = {
    case WorkProcessed(result: WorkResult) =>
      log.info("Worker -> Processed work: {}-{} | Work Id {}", result.deviceType, result.deviceId, workId)
      sendToMaster(WorkIsDone(workerId, workId, result))
      context.setReceiveTimeout(5.seconds)
      context.become(waitForWorkIsDoneAck(result))

    case work: Work =>
      log.info("Worker -> ALERT: Worker Id {} NOT AVAILABLE for Work Id {}", workerId, work.workId)
  }

  def waitForWorkIsDoneAck(result: WorkResult): Receive = {
    case Ack(id) if id == workId =>
      sendToMaster(WorkerRequestsWork(workerId))
      context.setReceiveTimeout(Duration.Undefined)
      context.become(idle)
    case ReceiveTimeout =>
      log.info("Worker -> ALERT: NO ACK from cluster master, retrying ... ")
      sendToMaster(WorkIsDone(workerId, workId, result))
  }

  override def unhandled(message: Any): Unit = message match {
    case Terminated(`workProcessor`) => context.stop(self)
    case WorkIsReady =>
    case _ => super.unhandled(message)
  }

  def sendToMaster(msg: Any): Unit = {
    clusterClient ! SendToAll("/user/master/singleton", msg)
  }
} 
Example 10
Source File: CacheDataActor.scala    From distributed-cache-on-k8s-poc   with MIT License 5 votes vote down vote up
package cluster

import java.util.UUID

import akka.actor.SupervisorStrategy.Stop
import akka.actor.{ Actor, ActorLogging, Props, ReceiveTimeout }
import akka.cluster.sharding.ShardRegion
import akka.cluster.sharding.ShardRegion.Passivate
import cluster.CacheDataActor.Get

class CacheDataActor extends Actor with ActorLogging {

  override def receive: Receive = {
    case Get(id) => sender ! s"cached data for id: $id"
    case ReceiveTimeout =>
      log.info(s"sending Passivate to metadata parent: {${context.parent.path.name}} for ${self.path.name}")
      context.parent ! Passivate(stopMessage = Stop)
    case Stop =>
      context.stop(self)
      log.info(s"Passivating metadata actor for ${self.path.name}")
  }
}

object CacheDataActor {
  final val numOfShards = 50 // Planned num of cluster nodes
  val extractEntityId: ShardRegion.ExtractEntityId = {
    case msg@Get(id) => (id.toString, msg)
  }
  val extractShardId: ShardRegion.ExtractShardId = {
    case Get(id) => (id.hashCode() % numOfShards).toString
  }

  case class Get(id: UUID)

  def props: Props = Props(new CacheDataActor())
} 
Example 11
Source File: dProcessManager.scala    From reactive-application-development-scala   with Apache License 2.0 5 votes vote down vote up
package com.airport

import akka.actor.{ReceiveTimeout, Actor, ActorRef}

import scala.concurrent.duration._

object BankTransferProcessProtocol {
  sealed trait BankTransferProcessMessage

  final case class TransferFunds(
    transactionId: String,
    fromAccount: ActorRef,
    toAccount: ActorRef,
    amount: Double) extends BankTransferProcessMessage
}

object BankTransferProcess {
  final case class FundsTransfered(transactionId: String)
  final case class TransferFailed(transactionId: String)
}

object AccountProtocol {
  sealed trait AccountProtocolMessage
  case class Withdraw(amount: Double) extends AccountProtocolMessage
  case class Deposit(amount: Double) extends AccountProtocolMessage
  final case object Acknowledgment
}

class BankTransferProcess extends Actor {

  import BankTransferProcess._
  import BankTransferProcessProtocol._
  import AccountProtocol._

  context.setReceiveTimeout(30.minutes)

  override def receive = {
    case TransferFunds(transactionId, fromAccount, toAccount, amount) =>
      fromAccount ! Withdraw(amount)
      val client = sender()
      context become awaitWithdrawal(transactionId, amount, toAccount, client)
  }

  def awaitWithdrawal(transactionId: String, amount: Double, toAccount: ActorRef, client: ActorRef): Receive = {
    case Acknowledgment =>
      toAccount ! Deposit(amount)
      context become awaitDeposit(transactionId, client)

    case ReceiveTimeout =>
      client ! TransferFailed(transactionId)
      context.stop(self)
  }

  def awaitDeposit(transactionId: String, client: ActorRef): Receive = {
    case Acknowledgment =>
      client ! FundsTransfered(transactionId)
      context.stop(self)

    case ReceiveTimeout =>
      client ! TransferFailed(transactionId)
      context.stop(self)
  }
} 
Example 12
Source File: FunctionInfoProviderRunner.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.master.jobs

import akka.actor.{Actor, ActorRef, ActorSystem, Props, ReceiveTimeout}
import io.hydrosphere.mist.core.CommonData
import io.hydrosphere.mist.core.CommonData.RegisterJobInfoProvider
import io.hydrosphere.mist.master.FunctionInfoProviderConfig

import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.concurrent.{Future, Promise}
import scala.sys.process.Process

class FunctionInfoProviderRunner(
  runTimeout: FiniteDuration,
  cacheEntryTtl: FiniteDuration,
  masterHost: String,
  clusterPort: Int,
  sparkConf: Map[String, String]
) extends WithSparkConfArgs {

  def run()(implicit system: ActorSystem): Future[ActorRef] = {
    val refWaiter = ActorRefWaiter(runTimeout)(system)
    val cmd =
      Seq(s"${sys.env("MIST_HOME")}/bin/mist-function-info-provider",
        "--master", masterHost,
        "--cluster-port", clusterPort.toString,
        "--cache-entry-ttl", cacheEntryTtl.toMillis.toString)

    val builder = Process(cmd, None, ("SPARK_CONF", sparkConfArgs(sparkConf).mkString(" ")))
    builder.run(false)
    refWaiter.waitRef()
  }
}

trait WithSparkConfArgs {

  def sparkConfArgs(sparkConf: Map[String, String]): Seq[String] = {
    sparkConf.map { case (k, v) => s"--conf $k=$v" }
      .toSeq
  }
}

trait ActorRefWaiter {
  def waitRef(): Future[ActorRef]
}

object ActorRefWaiter {

  class IdentityActor(pr: Promise[ActorRef], initTimeout: Duration) extends Actor {

    override def preStart(): Unit = {
      context.setReceiveTimeout(initTimeout)
    }

    override def receive: Receive = {
      case RegisterJobInfoProvider(ref) =>
        pr.success(ref)
        context stop self

      case ReceiveTimeout =>
        pr.failure(new IllegalStateException("Initialization of FunctionInfoProvider failed of timeout"))
        context stop self
    }
  }

  def apply(initTimeout: Duration)(implicit system: ActorSystem): ActorRefWaiter = new ActorRefWaiter {
    override def waitRef(): Future[ActorRef] = {
      val pr = Promise[ActorRef]
      system.actorOf(Props(new IdentityActor(pr, initTimeout)), CommonData.FunctionInfoProviderRegisterActorName)
      pr.future
    }
  }

}

object FunctionInfoProviderRunner {


  def create(config: FunctionInfoProviderConfig, masterHost: String, clusterPort: Int): FunctionInfoProviderRunner = {
    sys.env.get("SPARK_HOME") match {
      case Some(_) =>
        new FunctionInfoProviderRunner(config.runTimeout, config.cacheEntryTtl, masterHost, clusterPort, config.sparkConf)
      case None => throw new IllegalStateException("You should provide SPARK_HOME env variable for running mist")
    }

  }
} 
Example 13
Source File: RestartSupervisor.scala    From mist   with Apache License 2.0 5 votes vote down vote up
package io.hydrosphere.mist.utils.akka

import akka.pattern.pipe
import akka.actor.{Actor, ActorLogging, ActorRef, ActorRefFactory, Props, ReceiveTimeout, SupervisorStrategy, Terminated, Timers}
import io.hydrosphere.mist.utils.Logger

import scala.concurrent.{Future, Promise}
import scala.concurrent.duration._

class RestartSupervisor(
  name: String,
  start: () => Future[ActorRef],
  timeout: FiniteDuration,
  maxRetry: Int
) extends Actor with ActorLogging with Timers {

  override def receive: Receive = init

  import context._
  import RestartSupervisor._

  private def init: Receive = {
    case Event.Start(req) =>
      start().map(Event.Started) pipeTo self
      context become await(Some(req), 0)
  }

  private def await(req: Option[Promise[ActorRef]], attempts: Int): Receive = {
    case Event.Started(ref) =>
      req.foreach(_.success(self))
      context watch ref
      context become proxy(ref)

    case akka.actor.Status.Failure(e)  if maxRetry == attempts + 1 =>
      req.foreach(_.failure(e))
      log.error(e, "Starting child for {} failed, maxRetry reached", name)
      context stop self

    case akka.actor.Status.Failure(e) =>
      log.error(e, "Starting child for {} failed", name)
      timers.startSingleTimer("timeout", Event.Timeout, timeout)
      context become restartTimeout(req, attempts)
  }

  private def proxy(ref: ActorRef): Receive = {
    case Terminated(_) =>
      log.error(s"Reference for {} was terminated. Restarting", name)
      timers.startSingleTimer("timeout", Event.Timeout, timeout)
      context become restartTimeout(None, 0)

    case x => ref.forward(x)
  }

  private def restartTimeout(req: Option[Promise[ActorRef]], attempts: Int): Receive = {
    case Event.Timeout =>
      start().map(Event.Started) pipeTo self
      context become await(req, attempts + 1)
  }
}

object RestartSupervisor {

  sealed trait Event
  object Event {
    final case class Start(req: Promise[ActorRef]) extends Event
    case object Restart extends Event
    final case class Started(ref: ActorRef) extends Event
    case object Timeout extends Event
  }


  def props(
    name: String,
    start: () => Future[ActorRef],
    timeout: FiniteDuration,
    maxRetry: Int
  ): Props = {
    Props(classOf[RestartSupervisor], name, start, timeout, maxRetry)
  }

  def wrap(
    name: String,
    start: () => Future[ActorRef],
    timeout: FiniteDuration,
    maxRetry: Int
  )(implicit af: ActorRefFactory): Future[ActorRef] = {

    val ref = af.actorOf(props(name, start, timeout, maxRetry))
    val promise = Promise[ActorRef]
    ref ! Event.Start(promise)
    promise.future
  }

  def wrap(
    name: String,
    maxRetry: Int,
    start: () => Future[ActorRef]
  )(implicit af: ActorRefFactory): Future[ActorRef] = wrap(name, start, 5 seconds, maxRetry)(af)

} 
Example 14
Source File: FactorialFrontend.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package sample.cluster.factorial

import akka.actor.{ Actor, ActorLogging, ActorSystem, Props, ReceiveTimeout }
import akka.cluster.Cluster
import akka.routing.FromConfig
import com.typesafe.config.ConfigFactory

import scala.concurrent.Await
import scala.concurrent.duration._
import scala.util.Try

class FactorialFrontend(upToN: Int, repeat: Boolean) extends Actor with ActorLogging {
  val backend =
    context.actorOf(FromConfig.props(), name = "factorialBackendRouter")

  override def preStart(): Unit = {
    sendJobs()
    if (repeat) {
      context.setReceiveTimeout(10.seconds)
    }
  }

  def receive = {
    case (n: Int, factorial: BigInt) =>
      log.info("{}! = {}", n, factorial)
      if (n == upToN) {
        if (repeat) sendJobs()
        else context.stop(self)
      }
    case ReceiveTimeout =>
      log.info("Timeout")
      sendJobs()
  }

  def sendJobs(): Unit =
    //    log.info("Starting batch of factorials up to [{}]", upToN)
    1 to upToN foreach { backend ! _ }
}

object FactorialFrontend {
  def main(args: Array[String]): Unit = {
    val upToN = 200

    val config =
      ConfigFactory.parseString("akka.cluster.roles = [frontend]").withFallback(ConfigFactory.load("factorial"))

    val system = ActorSystem("ClusterSystem", config)
    system.log.info("Factorials will start when 2 backend members in the cluster.")

    Cluster(system) registerOnMemberUp {
      system.actorOf(Props(classOf[FactorialFrontend], upToN, false), name = "factorialFrontend")
    }

    Cluster(system).registerOnMemberRemoved {
      // exit JVM when ActorSystem has been terminated
      system.registerOnTermination(System.exit(0))
      // shut down ActorSystem
      system.terminate()

      // In case ActorSystem shutdown takes longer than 10 seconds,
      // exit the JVM forcefully anyway.
      // We must spawn a separate thread to not block current thread,
      // since that would have blocked the shutdown of the ActorSystem.
      new Thread {
        override def run(): Unit =
          if (Try(Await.ready(system.whenTerminated, 10.seconds)).isFailure)
            System.exit(-1)
      }.start()
    }
  }
} 
Example 15
Source File: StatsService.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package sample.cluster.stats

import akka.actor.{ Actor, ActorRef, Props, ReceiveTimeout }
import akka.routing.ConsistentHashingRouter.ConsistentHashableEnvelope
import akka.routing.FromConfig

import scala.concurrent.duration._

//#service
class StatsService extends Actor {
  // This router is used both with lookup and deploy of routees. If you
  // have a router with only lookup of routees you can use Props.empty
  // instead of Props[StatsWorker.class].
  val workerRouter =
    context.actorOf(FromConfig.props(Props[StatsWorker]), name = "workerRouter")

  def receive = {
    case StatsJob(text) if text != "" =>
      val words = text.split(" ")
      val replyTo = sender() // important to not close over sender()
      // create actor that collects replies from workers
      val aggregator =
        context.actorOf(Props(classOf[StatsAggregator], words.size, replyTo))
      words foreach { word =>
        workerRouter.tell(ConsistentHashableEnvelope(word, word), aggregator)
      }
  }
}

class StatsAggregator(expectedResults: Int, replyTo: ActorRef) extends Actor {
  var results = IndexedSeq.empty[Int]
  context.setReceiveTimeout(3.seconds)

  def receive = {
    case wordCount: Int =>
      results = results :+ wordCount
      if (results.size == expectedResults) {
        val meanWordLength = results.sum.toDouble / results.size
        replyTo ! StatsResult(meanWordLength)
        context.stop(self)
      }
    case ReceiveTimeout =>
      replyTo ! JobFailed("Service unavailable, try again later")
      context.stop(self)
  }
}
//#service 
Example 16
Source File: Sender.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package sample.remote.benchmark

import akka.actor.{ Actor, ActorIdentity, ActorRef, ActorSystem, Identify, Props, ReceiveTimeout, Terminated }
import com.typesafe.config.ConfigFactory

import scala.concurrent.duration._

class Sender(path: String, totalMessages: Int, burstSize: Int, payloadSize: Int) extends Actor {
  import Sender._
  val payload: Array[Byte] = Vector.fill(payloadSize)("a").mkString.getBytes
  println(s"payload bytes: ${payload.length}")
  var startTime = 0L
  var maxRoundTripMillis = 0L

  context.setReceiveTimeout(3.seconds) // 设置Actor自身接收消息超时时长
  sendIdentifyRequest() // 发请求确认远程actor的路径是否有效。

  override def receive: Receive = identifying

  def identifying: Receive = {
    case ActorIdentity(`path`, Some(actor)) =>
      context.watch(actor)
      context.become(active(actor))
      context.setReceiveTimeout(Duration.Undefined) // 重置超时时间
      self ! Warmup

    case ActorIdentity(`path`, None) =>
      println(s"远程actor无效:$path")

    case ReceiveTimeout =>
      sendIdentifyRequest() // 超时,再次确认远程actor是否有效
  }

  def active(actor: ActorRef): Receive = {
    case Warmup => // 热身,不计入统计
      sendBatch(actor, burstSize)
      actor ! Start

    case Start =>
      println(s"启动基准测试一共 $totalMessages 消息,分帧大小 $burstSize,有效负载 $payloadSize")
      startTime = System.nanoTime()
      val remaining = sendBatch(actor, totalMessages)
      if (remaining == 0)
        actor ! Done
      else
        actor ! Continue(remaining, startTime, startTime, burstSize)

    case c @ Continue(remaining, t0, t1, n) =>
      val now = System.nanoTime()
      val duration = (now - t0).nanos.toMillis // 从发出 Continue 指令到收到指令回复花费的时间
      val roundTripMillis = (now - t1).nanos.toMillis
      maxRoundTripMillis = math.max(maxRoundTripMillis, roundTripMillis)
      if (duration >= 500) { // 以500ms为间隔作统计
        val throughtput = (n * 1000.0 / duration).toInt
        println(s"花费 ${duration}ms 发送了 $n 条消息,吞吐量 ${throughtput}msg/s,")
      }

      val nextRemaining = sendBatch(actor, remaining)
      if (nextRemaining == 0)
        actor ! Done
      else if (duration >= 500) // 一个批次的数量已发完
        actor ! Continue(nextRemaining, now, now, burstSize)
      else // 间隔时间不足500ms,更新 剩余数量、(分帧)起始时间、分帧发送数量
        actor ! c.copy(remaining = nextRemaining, burstStartTime = now, n = n + burstSize)

    case Done =>
      val took = (System.nanoTime - startTime).nanos.toMillis
      val throughtput = (totalMessages * 1000.0 / took).toInt
      println(
        s"一共花费 ${took}ms 发送了 ${totalMessages}消息, 吞吐量 ${throughtput}msg/s, " +
        s"最大往返时间 ${maxRoundTripMillis}ms, 分帧数据大小 $burstSize, " +
        s"有效负载 $payloadSize")
      actor ! Shutdown

    case Terminated(`actor`) =>
      println("Receiver terminated")
      context.system.terminate()
  }

  
  case class Continue(remaining: Int, startTime: Long, burstStartTime: Long, n: Int) extends Echo

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("Sys", ConfigFactory.load("calculator"))
    val remoteHostPort = if (args.nonEmpty) args(0) else "127.0.0.1:2553"
    val remotePath = s"akka.tcp://Sys@$remoteHostPort/user/rcv"
    val totalMessages = if (args.length >= 2) args(1).toInt else 500000
    val burstSize = if (args.length >= 3) args(2).toInt else 5000
    val payloadSize = if (args.length >= 4) args(3).toInt else 100

    system.actorOf(Sender.props(remotePath, totalMessages, burstSize, payloadSize), "snd")
  }

  def props(path: String, totalMessages: Int, burstSize: Int, payloadSize: Int) =
    Props(new Sender(path, totalMessages, burstSize, payloadSize))
}