All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tasks.util.HeartBeat.scala Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License
 *
 * Copyright (c) 2015 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland,
 * Group Fellay
 * Modified work, Copyright (c) 2016 Istvan Bartha

 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software
 * is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package tasks.util

import akka.actor.{
  Actor,
  PoisonPill,
  ActorRef,
  Cancellable,
  ActorRefFactory,
  Props
}
import akka.remote.DeadlineFailureDetector
import akka.remote.DisassociatedEvent

import scala.concurrent.duration._

import tasks.util.eq._
import tasks.util.config._
import tasks.wire._

object HeartBeatActor {
  def watch[A](target: ActorRef, signal: A, listener: ActorRef)(implicit
      AS: ActorRefFactory,
      config: TasksConfig
  ) =
    AS.actorOf(
      Props(new HeartBeatActor(target, signal, listener))
        .withDispatcher("heartbeat")
    )
}

class HeartBeatActor(target: ActorRef, signal: Any, listener: ActorRef)(implicit
    config: TasksConfig
) extends Actor
    with akka.actor.ActorLogging {

  private case object CheckHeartBeat

  private var scheduledHeartBeats: Cancellable = null

  private val failureDetector = new DeadlineFailureDetector(
    config.acceptableHeartbeatPause,
    config.acceptableHeartbeatPause
  )

  override def preStart() = {
    log.debug(
      "HeartBeatActor start for: " + target + " " + failureDetector.acceptableHeartbeatPause
    )

    import context.dispatcher

    scheduledHeartBeats = context.system.scheduler.scheduleAtFixedRate(
      initialDelay = 0 seconds,
      interval = config.launcherActorHeartBeatInterval,
      receiver = self,
      message = CheckHeartBeat
    )

  }

  override def postStop() = {
    scheduledHeartBeats.cancel()
    log.info("HeartBeatActor stopped.")
  }

  private def targetDown(): Unit = {
    listener ! signal
    self ! PoisonPill
  }

  @scala.annotation.nowarn
  def receive = {
    case DisassociatedEvent(_, remoteAddress, _)
        if remoteAddress === target.path.address =>
      log.warning("DisassociatedEvent received. TargetDown.")
      targetDown()

    case CheckHeartBeat =>
      if (!failureDetector.isAvailable) {
        targetDown()
      } else {
        target ! Ping
      }

    case Pong =>
      failureDetector.heartbeat()

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy