akka.actor.typed.ActorRef Scala Examples

The following examples show how to use akka.actor.typed.ActorRef. 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: JobActor.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package mass.job.service.job

import akka.actor.typed.scaladsl.{ ActorContext, Behaviors }
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior }
import akka.cluster.typed.{ ClusterSingleton, ClusterSingletonSettings, SingletonActor }
import fusion.inject.guice.GuiceApplication
import fusion.json.CborSerializable
import helloscala.common.IntStatus
import mass.core.Constants
import mass.job.JobScheduler
import mass.job.service.job.JobActor.CommandReply
import mass.message.job._

import scala.concurrent.Future

object JobActor {
  sealed trait Command extends CborSerializable
  final case class CommandReply(message: JobMessage, replyTo: ActorRef[JobResponse]) extends Command
  final case class CommandEvent(event: JobEvent) extends Command

  val NAME = "job"

  def init(system: ActorSystem[_]): ActorRef[Command] = {
    ClusterSingleton(system).init(
      SingletonActor(apply(), NAME).withSettings(ClusterSingletonSettings(system).withRole(Constants.Roles.CONSOLE)))
  }

  private def apply(): Behavior[Command] = Behaviors.setup[Command](context => new JobActor(context).init())
}

import mass.job.service.job.JobActor._
class JobActor private (context: ActorContext[Command]) extends JobServiceComponent {
  import context.executionContext
  override val jobScheduler: JobScheduler = GuiceApplication(context.system).instance[JobScheduler]

  def init(): Behavior[Command] = {
    receive()
  }

  def receive(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case CommandReply(message, replyTo) =>
      receiveMessage(message).foreach(resp => replyTo ! resp)
      Behaviors.same
    case CommandEvent(event) =>
      receiveEvent(event)
      Behaviors.same
  }

  private def receiveMessage(message: JobMessage): Future[JobResponse] =
    try {
      val future = message match {
        case req: JobScheduleReq     => handleScheduleJob(req)
        case req: JobPageReq         => handlePage(req)
        case req: JobFindReq         => handleFind(req)
        case req: JobUploadJobReq    => handleUploadJob(req)
        case req: JobListReq         => handleList(req)
        case req: JobGetAllOptionReq => Future(handleGetAllOption(req))
        case req: JobCreateReq       => handleCreateJob(req)
        case req: JobUpdateReq       => handleUpdate(req)
        case req: JobUploadFilesReq  => handleUploadFiles(req)
      }
      future.recover {
        case e =>
          val message = s"Handle message error: ${e.getMessage}."
          logger.error(message, e)
          JobErrorResponse(IntStatus.INTERNAL_ERROR, message)
      }
    } catch {
      case e: Throwable =>
        val message = s"Process message error: ${e.getMessage}."
        logger.error(message)
        Future.successful(JobErrorResponse(IntStatus.INTERNAL_ERROR, message))
    }

  private def receiveEvent(v: JobEvent): Unit =
    try {
      v match {
        case event: JobTriggerEvent => triggerJob(event)
      }
    } catch {
      case e: Throwable => logger.error(s"Process event error: ${e.getMessage}", e)
    }
} 
Example 2
Source File: GettingStarted.scala    From lagom   with Apache License 2.0 5 votes vote down vote up
package docs.scaladsl.gettingstarted

package helloservice {
  //#helloservice
  import akka.Done
  import akka.NotUsed
  import com.lightbend.lagom.scaladsl.api._
  import play.api.libs.json._

  trait HelloService extends Service {
    def hello(id: String): ServiceCall[NotUsed, String]

    def useGreeting(id: String): ServiceCall[GreetingMessage, Done]

    final override def descriptor = {
      import Service._
      named("hello")
        .withCalls(
          pathCall("/api/hello/:id", hello _),
          pathCall("/api/hello/:id", useGreeting _)
        )
        .withAutoAcl(true)
    }
  }

  case class GreetingMessage(message: String)

  object GreetingMessage {
    implicit val format: Format[GreetingMessage] = Json.format[GreetingMessage]
  }
  //#helloservice

  //#helloserviceimpl
  import akka.actor.typed.ActorRef
  import akka.actor.typed.Behavior
  import com.lightbend.lagom.scaladsl.api.ServiceCall
  import akka.cluster.sharding.typed.scaladsl.ClusterSharding
  import akka.cluster.sharding.typed.scaladsl.EntityRef

  import scala.concurrent.ExecutionContext
  import scala.concurrent.duration._
  import akka.util.Timeout
  import com.lightbend.lagom.scaladsl.api.transport.BadRequest

  class HelloServiceImpl(clusterSharding: ClusterSharding)(implicit ec: ExecutionContext) extends HelloService {
    implicit val timeout = Timeout(5.seconds)

    override def hello(id: String): ServiceCall[NotUsed, String] = ServiceCall { _ =>
      entityRef(id)
        .ask[Greeting](replyTo => Hello(id, replyTo))
        .map(greeting => greeting.message)
    }

    override def useGreeting(id: String) = ServiceCall { request =>
      entityRef(id)
        .ask[Confirmation](replyTo => UseGreetingMessage(request.message, replyTo))
        .map {
          case Accepted => Done
          case _        => throw BadRequest("Can't upgrade the greeting message.")
        }
    }

    private def entityRef(id: String): EntityRef[HelloWorldCommand] =
      clusterSharding.entityRefFor(HelloWorldState.typeKey, id)
  }
  //#helloserviceimpl

  import com.lightbend.lagom.scaladsl.persistence.PersistentEntity.ReplyType
  import com.lightbend.lagom.scaladsl.persistence.PersistentEntity

  sealed trait HelloWorldCommand
  case class UseGreetingMessage(message: String, replyTo: ActorRef[Confirmation]) extends HelloWorldCommand
  case class Hello(name: String, replyTo: ActorRef[Greeting])                     extends HelloWorldCommand

  final case class Greeting(message: String)
  sealed trait Confirmation
  sealed trait Accepted               extends Confirmation
  case object Accepted                extends Accepted
  case class Rejected(reason: String) extends Confirmation

  sealed trait HelloWorldEvent
  case class GreetingMessageChanged(message: String) extends HelloWorldEvent

  object HelloWorldState {
    import akka.cluster.sharding.typed.scaladsl.EntityTypeKey
    val typeKey = EntityTypeKey[HelloWorldCommand]("HelloWorldAggregate")
  }
} 
Example 3
Source File: ForkJoinCreation.scala    From effpi   with MIT License 5 votes vote down vote up
// Effpi - verified message-passing programs in Dotty
// Copyright 2019 Alceste Scalas and Elias Benussi
// Released under the MIT License: https://opensource.org/licenses/MIT
package effpi.benchmarks.akka

import akka.NotUsed
import akka.actor.typed.scaladsl.{ Behaviors, MutableBehavior, ActorContext}
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, DispatcherSelector, Terminated }

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.concurrent.{ Future, Promise, Await }
import scala.concurrent.ExecutionContext.Implicits.global

object ForkJoinCreation {

  case class Message(msg: String)

  val simpleActor = Behaviors.receive[Message] { (ctx, msg) =>
    Behaviors.stopped
  }

  def mainActor(
    durationPromise: Promise[Long], numActors: Int
  ): Behavior[akka.NotUsed] =
    Behaviors.setup { ctx =>

      val startTime = System.nanoTime()

      val simpleActorRefs = (1 to numActors).toList.map { id =>
        ctx.spawn(simpleActor, "simple" + id)
      }

      simpleActorRefs.foreach { simpleActorRef =>
        simpleActorRef ! Message("Hello World!")
      }

      val endTime = System.nanoTime()

      durationPromise.success(endTime - startTime)
      Behaviors.stopped
    }

  def bench(params: Int): Long = {
    val durationPromise = Promise[Long]()
    val durationFuture = durationPromise.future
    val system = ActorSystem(
      mainActor(durationPromise, params), "ForkJoinCreationDemo")
    Await.result(system.whenTerminated, Duration.Inf)
    val duration = Await.result(durationFuture, Duration.Inf)
    duration
  }

} 
Example 4
Source File: PingPong.scala    From effpi   with MIT License 5 votes vote down vote up
// Effpi - verified message-passing programs in Dotty
// Copyright 2019 Alceste Scalas and Elias Benussi
// Released under the MIT License: https://opensource.org/licenses/MIT
package effpi.benchmarks.akka

import akka.NotUsed
import akka.actor.typed.scaladsl.{ Behaviors, MutableBehavior, ActorContext}
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, DispatcherSelector, Terminated }
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.concurrent.{ Future, Promise, Await }
import scala.concurrent.ExecutionContext.Implicits.global

object PingPong {

  final case class Ping(iterations: Int, replyTo: ActorRef[Pong])

  case class Pong(iterations: Int, pingTo: ActorRef[Ping])

  val pong = Behaviors.receive[Ping] { (ctx, msg) =>
    msg.replyTo ! Pong(msg.iterations - 1, ctx.self)
    Behaviors.same
  }

  def ping(startTimePromise: Promise[Long], endTimePromise: Promise[Long], expectedIterations: Int) = Behaviors.receive[Pong] { (ctx, pong) =>
    if (pong.iterations == 0) {
      endTimePromise.success(System.nanoTime())
      Behaviors.stopped
    } else {
      if (expectedIterations == pong.iterations) {
        startTimePromise.success(System.nanoTime())
      }
      pong.pingTo ! Ping(pong.iterations, ctx.self)
      Behaviors.same
    }
  }

  def mainActor(
    durationPromise: Promise[Long],
    numPairs: Int,
    numIterations: Int
  ): Behavior[akka.NotUsed] =
    Behaviors.setup { ctx =>

      val (startTimePromises, startTimeFutures): (List[Promise[Long]], List[Future[Long]]) = (1 to numPairs).toList.map { _ =>
        val startTimePromise = Promise[Long]()
        val startTimeFuture = startTimePromise.future

        (startTimePromise, startTimeFuture)
      }.unzip

      val (endTimePromises, endTimeFutures): (List[Promise[Long]], List[Future[Long]]) = (1 to numPairs).toList.map { _ =>
        val endTimePromise = Promise[Long]()
        val endTimeFuture = endTimePromise.future

        (endTimePromise, endTimeFuture)
      }.unzip

      // val refs = (1 to numPairs).toList.map { id =>
      val refs = startTimePromises.zip(endTimePromises).zipWithIndex.map { (promises, id) =>
        val (sPromise, ePromise) = promises
        val pongRef = ctx.spawn(pong, "pong" + id)
        val pingRef = ctx.spawn(ping(sPromise, ePromise, numIterations), "ping" + id)
        ctx.watch(pingRef)
        (pingRef, pongRef)
      }
      refs.foreach { (pingRef, pongRef) => pingRef ! Pong(numIterations, pongRef) }

      val startTimes = Await.result(Future.sequence(startTimeFutures), Duration.Inf)
      val startTime = startTimes.min
      val endTimes = Await.result(Future.sequence(endTimeFutures), Duration.Inf)
      val endTime = endTimes.max
      durationPromise.success(endTime - startTime)
      val pingPongDuration = endTime - startTime

      var terminatedProcesses = 0
      Behaviors.receiveSignal {
        case (_, Terminated(ref)) =>
          terminatedProcesses = terminatedProcesses + 1
          if (terminatedProcesses == numPairs) {
            Behaviors.stopped
          } else {
            Behaviors.same
          }
          Behaviors.stopped
        case (_, _) =>
          Behaviors.empty
      }
    }

  def bench(params: (Int, Int)): Long = {
    val (numPairs, numIterations) = params
    val durationPromise = Promise[Long]()
    val durationFuture = durationPromise.future
    val system = ActorSystem(
      mainActor(durationPromise, numPairs, numIterations), "PingPongDemo")
    Await.result(system.whenTerminated, Duration.Inf)
    val duration = Await.result(durationFuture, Duration.Inf)
    duration
  }
} 
Example 5
Source File: CountingActor.scala    From effpi   with MIT License 5 votes vote down vote up
// Effpi - verified message-passing programs in Dotty
// Copyright 2019 Alceste Scalas and Elias Benussi
// Released under the MIT License: https://opensource.org/licenses/MIT
package effpi.benchmarks.akka

import akka.NotUsed
import akka.actor.typed.scaladsl.{ Behaviors, MutableBehavior, ActorContext}
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, DispatcherSelector, Terminated }

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.concurrent.{ Future, Promise, Await }
import scala.concurrent.ExecutionContext.Implicits.global

object CountingActor {

  sealed trait CounterAction
  object CounterAction {
    final case class Add(num: Int, p: Promise[Int]) extends CounterAction
    final case class Cheque(replyTo: ActorRef[Sum]) extends CounterAction
  }

  case class Sum(sum: Int)

  val counter = Behaviors.setup[CounterAction] { ctx =>
    new MutableCounter(ctx)
  }

  class MutableCounter(
    ctx: ActorContext[CounterAction]
  ) extends MutableBehavior[CounterAction] {
    var counter = 0

    override def onMessage(msg: CounterAction): Behavior[CounterAction] = {
      msg match {
        case CounterAction.Add(num, p) =>
          counter += 1
          p.success(num)
          Behaviors.same
        case CounterAction.Cheque(replyTo) =>
          replyTo ! Sum(counter)
          Behaviors.stopped
      }
    }
  }

  def sink(endTimePromise: Promise[Long]) = Behaviors.receive[Sum] { (ctx, msg) =>
    endTimePromise.success(System.nanoTime())
    Behaviors.stopped
  }

  def mainActor(
    durationPromise: Promise[Long],
    numMessages: Int
  ): Behavior[akka.NotUsed] =
    Behaviors.setup { ctx =>

      val endTimePromise = Promise[Long]()
      val endTimeFuture = endTimePromise.future

      val sinkRef = ctx.spawn(sink(endTimePromise), "sink")
      ctx.watch(sinkRef)
      val counterRef = ctx.spawn(counter, "counter")

      val startTime = System.nanoTime()
      val futs = (1 to numMessages).toList.map { num =>
        val p = Promise[Int]()
        val f = p.future
        counterRef ! CounterAction.Add(num, p)
        f
      }

      Await.result(Future.sequence(futs), Duration.Inf)

      counterRef ! CounterAction.Cheque(sinkRef)

      val endTime = Await.result(endTimeFuture, Duration.Inf)
      val countingDuration = endTime - startTime
      durationPromise.success(countingDuration)

      Behaviors.receiveSignal {
        case (_, Terminated(ref)) =>
          Behaviors.stopped
        case (_, _) =>
          Behaviors.empty
      }
    }

  def bench(params: Int): Long = {
    val durationPromise = Promise[Long]()
    val durationFuture = durationPromise.future
    val system = ActorSystem(
      mainActor(durationPromise, params), "CountingActorDemo")
    Await.result(system.whenTerminated, Duration.Inf)
    val duration = Await.result(durationFuture, Duration.Inf)
    duration
  }
} 
Example 6
Source File: ForkJoinThroughput.scala    From effpi   with MIT License 5 votes vote down vote up
// Effpi - verified message-passing programs in Dotty
// Copyright 2019 Alceste Scalas and Elias Benussi
// Released under the MIT License: https://opensource.org/licenses/MIT
package effpi.benchmarks.akka

import akka.NotUsed
import akka.actor.typed.scaladsl.{ Behaviors, MutableBehavior, ActorContext}
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, DispatcherSelector, Terminated }
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.concurrent.{ Future, Promise, Await }
import scala.concurrent.ExecutionContext.Implicits.global

object ForkJoinThroughput {

  case class Message(msg: String)

  def receiver(maxMsgs: Int) = Behaviors.setup[Message] { ctx =>
    new MutableSimpleActor(ctx, maxMsgs)
  }

  class MutableSimpleActor(
    ctx: ActorContext[Message],
    maxMsgs: Int
  ) extends MutableBehavior[Message] {
    var count = 0

    override def onMessage(msg: Message): Behavior[Message] = {
      count +=1
      if (count < maxMsgs) {
        Behaviors.same
      } else {
        Behaviors.stopped
      }
    }
  }

  def mainActor(
    durationPromise: Promise[Long],
    numActors: Int,
    numMessages: Int
  ): Behavior[akka.NotUsed] =
    Behaviors.setup { ctx =>

      val receiversRef = (1 to numActors).map{ id => ctx.spawn(receiver(numMessages), "receiver" + id)}

      val startTime = System.nanoTime()

      (1 to numMessages).foreach { n =>
        receiversRef.foreach { simpleActor =>
          simpleActor ! Message("Hello World!")
        }
      }

      val endTime = System.nanoTime()

      durationPromise.success(endTime - startTime)
      Behaviors.stopped
    }

  def bench(params: (Int, Int)): Long = {
    val (numActors, numMessages) = params
    val durationPromise = Promise[Long]()
    val durationFuture = durationPromise.future
    val system = ActorSystem(
      mainActor(durationPromise, numActors, numMessages),
      "ForkJoinCreationDemo")
    Await.result(system.whenTerminated, Duration.Inf)
    val duration = Await.result(durationFuture, Duration.Inf)
    duration
  }
} 
Example 7
Source File: Main.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.example

import akka.actor.typed.{ ActorRef, ActorSystem }
import akka.actor.typed.scaladsl.Behaviors
import akka.cluster.sharding.typed.ShardingEnvelope
import akka.cluster.typed.{ Cluster, SelfUp, Subscribe }
import akka.management.cluster.bootstrap.ClusterBootstrap
import akka.management.scaladsl.AkkaManagement
import akka.persistence.cassandra.example.LoadGenerator.Start
import akka.actor.typed.scaladsl.LoggerOps
import akka.stream.alpakka.cassandra.scaladsl.CassandraSessionRegistry

import scala.concurrent.Await
import scala.concurrent.duration._

object Main {

  def main(args: Array[String]): Unit = {

    ActorSystem(Behaviors.setup[SelfUp] {
      ctx =>
        val readSettings = ReadSide.Settings(ctx.system.settings.config.getConfig("cassandra.example"))
        val writeSettings = ConfigurablePersistentActor.Settings(readSettings.nrTags)
        val loadSettings = LoadGenerator.Settings(ctx.system.settings.config.getConfig("cassandra.example"))

        AkkaManagement(ctx.system).start()
        ClusterBootstrap(ctx.system).start()
        val cluster = Cluster(ctx.system)
        cluster.subscriptions ! Subscribe(ctx.self, classOf[SelfUp])

        val topic = ReadSideTopic.init(ctx)

        if (cluster.selfMember.hasRole("read")) {
          val session = CassandraSessionRegistry(ctx.system).sessionFor("akka.persistence.cassandra")
          val offsetTableStmt =
            """
              CREATE TABLE IF NOT EXISTS akka.offsetStore (
                eventProcessorId text,
                tag text,
                timeUuidOffset timeuuid,
                PRIMARY KEY (eventProcessorId, tag)
              )
           """

          Await.ready(session.executeDDL(offsetTableStmt), 30.seconds)
        }

        Behaviors.receiveMessage {
          case SelfUp(state) =>
            ctx.log.infoN(
              "Cluster member joined. Initializing persistent actors. Roles {}. Members {}",
              cluster.selfMember.roles,
              state.members)
            val ref = ConfigurablePersistentActor.init(writeSettings, ctx.system)
            if (cluster.selfMember.hasRole("read")) {
              ctx.spawnAnonymous(Reporter(topic))
            }
            ReadSide(ctx.system, topic, readSettings)
            if (cluster.selfMember.hasRole("load")) {
              ctx.log.info("Starting load generation")
              val load = ctx.spawn(LoadGenerator(loadSettings, ref), "load-generator")
              load ! Start(10.seconds)
            }
            Behaviors.empty
        }
    }, "apc-example")
  }
} 
Example 8
Source File: LoadGenerator.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.example

import akka.actor.typed.{ ActorRef, Behavior }
import akka.actor.typed.scaladsl.Behaviors
import akka.cluster.sharding.typed.ShardingEnvelope
import com.typesafe.config.Config

import scala.concurrent.duration.FiniteDuration
import scala.util.Random
import akka.util.JavaDurationConverters._

object LoadGenerator {

  object Settings {
    def apply(config: Config): Settings = {
      Settings(config.getInt("persistence-ids"), config.getDuration("load-tick-duration").asScala)
    }
  }

  case class Settings(nrPersistenceIds: Int, tickDuration: FiniteDuration)

  sealed trait Command
  final case class Start(duration: FiniteDuration) extends Command
  final case class Tick() extends Command
  private case object Stop extends Command

  def apply(
      settings: Settings,
      ref: ActorRef[ShardingEnvelope[ConfigurablePersistentActor.Event]]): Behavior[Command] = {
    Behaviors.withTimers { timers =>
      Behaviors.setup { ctx =>
        Behaviors.receiveMessage {
          case Start(duration) =>
            ctx.log.info("Starting...")
            timers.startTimerAtFixedRate(Tick(), settings.tickDuration)
            timers.startSingleTimer(Stop, duration)
            Behaviors.same
          case Tick() =>
            ctx.log.info("Sending event")
            ref ! ShardingEnvelope(
              s"p${Random.nextInt(settings.nrPersistenceIds)}",
              ConfigurablePersistentActor.Event())
            Behaviors.same
          case Stop =>
            Behaviors.same
        }
      }
    }
  }
} 
Example 9
Source File: ConfigurablePersistentActor.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.example

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior }
import akka.cluster.sharding.typed.ShardingEnvelope
import akka.cluster.sharding.typed.scaladsl.{ ClusterSharding, Entity, EntityTypeKey }
import akka.persistence.typed.PersistenceId
import akka.persistence.typed.scaladsl.{ Effect, EventSourcedBehavior }

object ConfigurablePersistentActor {

  case class Settings(nrTags: Int)

  val Key: EntityTypeKey[Event] = EntityTypeKey[Event]("configurable")

  def init(settings: Settings, system: ActorSystem[_]): ActorRef[ShardingEnvelope[Event]] = {
    ClusterSharding(system).init(Entity(Key)(ctx => apply(settings, ctx.entityId)).withRole("write"))
  }

  final case class Event(timeCreated: Long = System.currentTimeMillis()) extends CborSerializable

  final case class State(eventsProcessed: Long) extends CborSerializable

  def apply(settings: Settings, persistenceId: String): Behavior[Event] =
    Behaviors.setup { ctx =>
      EventSourcedBehavior[Event, Event, State](
        persistenceId = PersistenceId.ofUniqueId(persistenceId),
        State(0),
        (_, event) => {
          ctx.log.info("persisting event {}", event)
          Effect.persist(event)
        },
        (state, _) => state.copy(eventsProcessed = state.eventsProcessed + 1)).withTagger(event =>
        Set("tag-" + math.abs(event.hashCode() % settings.nrTags)))
    }

} 
Example 10
Source File: Reporter.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.example

import akka.actor.typed.{ ActorRef, Behavior }
import akka.actor.typed.pubsub.Topic
import akka.actor.typed.scaladsl.Behaviors
import akka.persistence.cassandra.example.ReadSideTopic.ReadSideMetrics
import akka.actor.typed.scaladsl.LoggerOps

object Reporter {
  def apply(topic: ActorRef[Topic.Command[ReadSideTopic.ReadSideMetrics]]): Behavior[ReadSideMetrics] =
    Behaviors.setup { ctx =>
      ctx.log.info("Subscribing to latency stats")
      topic ! Topic.Subscribe(ctx.self)
      Behaviors.receiveMessage[ReadSideMetrics] {
        case ReadSideMetrics(count, max, p99, p50) =>
          ctx.log.infoN("Read side Count: {} Max: {} p99: {} p50: {}", count, max, p99, p50)
          Behaviors.same
      }
    }
} 
Example 11
Source File: ReadSide.scala    From akka-persistence-cassandra   with Apache License 2.0 5 votes vote down vote up
package akka.persistence.cassandra.example

import akka.actor.typed.pubsub.Topic
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, PostStop }
import akka.cluster.sharding.typed.{ ClusterShardingSettings, ShardedDaemonProcessSettings }
import akka.cluster.sharding.typed.scaladsl.ShardedDaemonProcess
import akka.stream.{ KillSwitches, SharedKillSwitch }
import com.typesafe.config.Config
import org.HdrHistogram.Histogram
import akka.actor.typed.scaladsl.LoggerOps
import scala.concurrent.duration._

object ReadSide {

  sealed trait Command
  private case object ReportMetrics extends Command

  object Settings {
    def apply(config: Config): Settings =
      Settings(config.getInt("processors"), config.getInt("tags-per-processor"))
  }

  case class Settings(nrProcessors: Int, tagsPerProcessor: Int) {
    val nrTags: Int = nrProcessors * tagsPerProcessor
  }

  def apply(
      system: ActorSystem[_],
      topic: ActorRef[Topic.Command[ReadSideTopic.ReadSideMetrics]],
      settings: Settings): Unit = {
    system.log.info("Running {} processors", settings.nrProcessors)
    val killSwitch: SharedKillSwitch = KillSwitches.shared("eventProcessorSwitch")
    ShardedDaemonProcess(system).init(
      "tag-processor",
      settings.nrProcessors - 1, // bug that creates +1 processor FIXME remove in 2.6.5
      i => behavior(topic, i, settings, killSwitch),
      ShardedDaemonProcessSettings(system).withShardingSettings(ClusterShardingSettings(system).withRole("read")),
      None)
  }

  private def behavior(
      topic: ActorRef[Topic.Command[ReadSideTopic.ReadSideMetrics]],
      nr: Int,
      settings: Settings,
      killSwitch: SharedKillSwitch): Behavior[Command] =
    Behaviors.withTimers { timers =>
      timers.startTimerAtFixedRate(ReportMetrics, 10.second)
      Behaviors.setup { ctx =>
        val start = (settings.tagsPerProcessor * nr)
        val end = start + (settings.tagsPerProcessor) - 1
        val tags = (start to end).map(i => s"tag-$i")
        ctx.log.info("Processor {} processing tags {}", nr, tags)
        // milliseconds, highest value = 1 minute
        val histogram = new Histogram(10 * 1000 * 60, 2)
        // maybe easier to just have these as different actors
        // my thinking is we can start with a large number of tags and scale out
        // read side processors later
        // having more tags will also increase write throughput/latency as it'll write to
        // many partitions
        // downside is running many streams/queries against c*
        tags.foreach(
          tag =>
            new EventProcessorStream[ConfigurablePersistentActor.Event](
              ctx.system,
              ctx.executionContext,
              s"processor-$nr",
              tag).runQueryStream(killSwitch, histogram))

        Behaviors
          .receiveMessage[Command] {
            case ReportMetrics =>
              if (histogram.getTotalCount > 0) {
                topic ! Topic.Publish(
                  ReadSideTopic.ReadSideMetrics(
                    histogram.getTotalCount,
                    histogram.getMaxValue,
                    histogram.getValueAtPercentile(99),
                    histogram.getValueAtPercentile(50)))
                histogram.reset()
              }
              Behaviors.same
          }
          .receiveSignal {
            case (_, PostStop) =>
              killSwitch.shutdown()
              Behaviors.same
          }
      }
    }

} 
Example 12
Source File: StrimziClusterWatcher.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter.watchers

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import com.lightbend.kafkalagexporter.{KafkaCluster, KafkaClusterManager}

object StrimziClusterWatcher {
  val name: String = "strimzi"

  def init(handler: ActorRef[KafkaClusterManager.Message]): Behavior[Watcher.Message] = Behaviors.setup { context =>
    val watcher = new Watcher.Events {
      override def added(cluster: KafkaCluster): Unit = handler ! KafkaClusterManager.ClusterAdded(cluster)
      override def removed(cluster: KafkaCluster): Unit = handler ! KafkaClusterManager.ClusterAdded(cluster)
      override def error(e: Throwable): Unit = context.log.error(e.getMessage, e)
    }
    val client = StrimziClient(watcher)
    watch(client)
  }

  def watch(client: Watcher.Client): Behaviors.Receive[Watcher.Message] = Behaviors.receive {
    case (context, _: Watcher.Stop) =>
      Behaviors.stopped { () =>
        client.close()
        context.log.info("Gracefully stopped StrimziKafkaWatcher")
      }
  }
} 
Example 13
Source File: Watcher.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter.watchers

import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.ActorContext
import com.lightbend.kafkalagexporter.{AppConfig, KafkaCluster}
import com.lightbend.kafkalagexporter.KafkaClusterManager

object Watcher {

  sealed trait Message
  sealed trait Stop extends Message
  final case object Stop extends Stop

  trait Client {
    def close(): Unit
  }

  trait Events {
    def added(cluster: KafkaCluster): Unit
    def removed(cluster: KafkaCluster): Unit
    def error(e: Throwable): Unit
  }

  def createClusterWatchers(context: ActorContext[KafkaClusterManager.Message],
                            appConfig: AppConfig): Seq[ActorRef[Watcher.Message]] = {
    // Add additional watchers here..
    val configMap = Seq(StrimziClusterWatcher.name -> appConfig.strimziWatcher)
    configMap.flatMap {
      case (StrimziClusterWatcher.name, true) =>
        context.log.info(s"Adding watcher: ${StrimziClusterWatcher.name}")
        Seq(context.spawn(StrimziClusterWatcher.init(context.self), s"strimzi-cluster-watcher-${StrimziClusterWatcher.name}"))
      case _ => Seq()
    }
  }
} 
Example 14
Source File: MetricsSink.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter

import akka.actor.typed.ActorRef
import com.lightbend.kafkalagexporter.MetricsSink._

object MetricsSink {
  trait Message
  final case class Stop(sender: ActorRef[KafkaClusterManager.Message]) extends MetricsSink.Message

  final case class GaugeDefinition(name: String, help: String, labels: List[String])
  type MetricDefinitions = List[GaugeDefinition]

  trait ClusterMetric extends Metric{
    def clusterName: String
  }

  trait Metric {
    def labels: List[String]
    def definition: GaugeDefinition
  }

  trait MetricValue extends ClusterMetric {
    def value: Double
  }

  trait RemoveMetric extends ClusterMetric
}

trait MetricsSink {
  def report(m: MetricValue): Unit
  def remove(m: RemoveMetric): Unit
  def stop(): Unit = ()
} 
Example 15
Source File: KafkaClusterManager.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior, ChildFailed}
import akka.util.Timeout
import com.lightbend.kafkalagexporter.KafkaClient.KafkaClientContract
import com.lightbend.kafkalagexporter.watchers.Watcher

import scala.concurrent.duration._
import scala.util.{Failure, Success}

object KafkaClusterManager {
  sealed trait Message
  sealed trait Stop extends Message
  final case object Stop extends Stop
  sealed trait Done extends Message
  final case object Done extends Done
  final case class ClusterAdded(c: KafkaCluster) extends Message
  final case class ClusterRemoved(c: KafkaCluster) extends Message
  final case class NamedCreator(name: String, creator: () => MetricsSink)


  private val stopTimeout: Timeout = 3.seconds

  def init(
            appConfig: AppConfig,
            metricsSinks: List[NamedCreator],
            clientCreator: KafkaCluster => KafkaClientContract): Behavior[Message] = Behaviors.setup { context =>

    context.log.info("Starting Kafka Lag Exporter with configuration: \n{}", appConfig)

    if (appConfig.clusters.isEmpty && !appConfig.strimziWatcher)
      context.log.info("No watchers are defined and no clusters are statically configured.  Nothing to do.")

    val watchers: Seq[ActorRef[Watcher.Message]] = Watcher.createClusterWatchers(context, appConfig)
    val reporters: List[ActorRef[MetricsSink.Message]] = metricsSinks.map { metricsSink : NamedCreator =>
      context.spawn(MetricsReporter.init(metricsSink.creator()), metricsSink.name)
    }
    appConfig.clusters.foreach(cluster => context.self ! ClusterAdded(cluster))

    reporters.map { context.watch }

    manager(appConfig, clientCreator, reporters, collectors = Map.empty, watchers)
  }

  def manager(
               appConfig: AppConfig,
               clientCreator: KafkaCluster => KafkaClientContract,
               reporters: List[ActorRef[MetricsSink.Message]],
               collectors: Map[KafkaCluster, ActorRef[ConsumerGroupCollector.Message]],
               watchers: Seq[ActorRef[Watcher.Message]]): Behavior[Message] =
    Behaviors.receive[Message] {
      case (context, ClusterAdded(cluster)) =>
        context.log.info(s"Cluster Added: $cluster")

        val config = ConsumerGroupCollector.CollectorConfig(
          appConfig.pollInterval,
          appConfig.lookupTableSize,
          cluster
        )
        val collector = context.spawn(
          ConsumerGroupCollector.init(config, clientCreator, reporters),
          s"consumer-group-collector-${cluster.name}"
        )

        manager(appConfig, clientCreator, reporters, collectors + (cluster -> collector), watchers)

      case (context, ClusterRemoved(cluster)) =>
        context.log.info(s"Cluster Removed: $cluster")

        collectors.get(cluster) match {
          case Some(collector) =>
            collector ! ConsumerGroupCollector.Stop
            manager(appConfig, clientCreator, reporters, collectors - cluster, watchers)
          case None =>
            manager(appConfig, clientCreator, reporters, collectors, watchers)
        }

      case (context, _: Stop) =>
        context.log.info("Attempting graceful shutdown")
        watchers.foreach(_ ! Watcher.Stop)
        collectors.foreach { case (_, collector) => collector ! ConsumerGroupCollector.Stop }
        implicit val timeout = stopTimeout
        reporters.foreach { reporter =>
          context.ask(reporter, (_: ActorRef[MetricsSink.Message]) => MetricsSink.Stop(context.self)) {
            case Success(_) => Done
            case Failure(ex) =>
              context.log.error("The metrics reporter shutdown failed.", ex)
              Done
          }
        }
        Behaviors.same
      case (_, _: Done) =>
        Behaviors.stopped
    } receiveSignal {
      case (context, ChildFailed(`reporters`, cause)) =>
        context.log.error("The metrics reporter failed.  Shutting down.", cause)
        context.self ! Stop
        Behaviors.same
    }
} 
Example 16
Source File: JobService.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package mass.job.service.job

import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.{ Files, Path }

import akka.actor.typed.{ ActorRef, ActorSystem }
import akka.actor.typed.scaladsl.AskPattern._
import akka.http.scaladsl.server.directives.FileInfo
import akka.util.Timeout
import javax.inject.{ Inject, Singleton }
import mass.job.service.job.JobActor.CommandReply
import mass.message.job._

import scala.collection.immutable
import scala.concurrent.duration._
import scala.concurrent.{ ExecutionContext, Future }
import scala.reflect.ClassTag

@Singleton
class JobService @Inject() (implicit system: ActorSystem[_]) {
  implicit val timeout: Timeout = Timeout(10.seconds)
  val jobActor: ActorRef[JobActor.Command] = JobActor.init(system)

  def listOption(): Future[JobGetAllOptionResp] = askToJob[JobGetAllOptionResp](JobGetAllOptionReq())

  def uploadFiles(list: immutable.Seq[(FileInfo, File)])(implicit ec: ExecutionContext): Future[JobUploadFilesResp] = {
    askToJob[JobUploadFilesResp](JobUploadFilesReq(list)).andThen {
      case _ => list.foreach { case (_, file) => Files.deleteIfExists(file.toPath) }
    }
  }

  def uploadJobOnZip(fileInfo: FileInfo, file: Path)(implicit ec: ExecutionContext): Future[JobUploadJobResp] = {
    val req = JobUploadJobReq(
      file,
      fileInfo.fileName,
      fileInfo.contentType.charsetOption.map(_.nioCharset()).getOrElse(StandardCharsets.UTF_8))
    askToJob[JobUploadJobResp](req).andThen { case _ => Files.deleteIfExists(file) }
  }

  def updateTrigger(req: JobUpdateReq): Future[JobSchedulerResp] = askToJob[JobSchedulerResp](req)

  def page(req: JobPageReq): Future[JobPageResp] = askToJob[JobPageResp](req)

  def findItemByKey(key: String): Future[JobSchedulerResp] = askToJob[JobSchedulerResp](JobFindReq(key = key))

  def createJob(req: JobCreateReq): Future[JobCreateResp] = askToJob[JobCreateResp](req)

  def updateJob(req: JobUpdateReq): Future[JobSchedulerResp] = askToJob[JobSchedulerResp](req)

  @inline private def askToJob[RESP](req: JobMessage)(implicit tag: ClassTag[RESP]): Future[RESP] =
    jobActor.ask[JobResponse](replyTo => CommandReply(req, replyTo)).mapTo[RESP]
} 
Example 17
Source File: ShoppingCartServiceImpl.scala    From lagom   with Apache License 2.0 5 votes vote down vote up
package com.example.shoppingcart.impl

import java.time.OffsetDateTime

import akka.Done
import akka.NotUsed
import com.example.shoppingcart.api.ShoppingCartService
import com.lightbend.lagom.scaladsl.api.ServiceCall
import com.lightbend.lagom.scaladsl.api.broker.Topic
import com.lightbend.lagom.scaladsl.api.transport.BadRequest
import com.lightbend.lagom.scaladsl.api.transport.NotFound
import com.lightbend.lagom.scaladsl.api.transport.TransportException
import com.lightbend.lagom.scaladsl.persistence.EventStreamElement

import scala.concurrent.ExecutionContext
import akka.cluster.sharding.typed.scaladsl.ClusterSharding
import scala.concurrent.duration._
import akka.util.Timeout
import akka.cluster.sharding.typed.scaladsl.EntityRef
import akka.actor.typed.ActorRef


  private def entityRef(id: String): EntityRef[ShoppingCartCommand] =
    clusterSharding.entityRefFor(ShoppingCart.typeKey, id)

  implicit val timeout = Timeout(5.seconds)

  override def get(id: String): ServiceCall[NotUsed, String] = ServiceCall { _ =>
    entityRef(id)
      .ask { reply: ActorRef[Summary] => Get(reply) }
      .map { cart => asShoppingCartView(id, cart) }
  }
  //#akka-persistence-reffor-after

  override def updateItem(id: String, productId: String, qty: Int): ServiceCall[NotUsed, String] = ServiceCall { update =>
    entityRef(id)
      .ask { replyTo: ActorRef[Confirmation] => UpdateItem(productId, qty, replyTo) }
      .map {
        case Accepted(summary)  => asShoppingCartView(id, summary)
        case Rejected(reason)   => throw BadRequest(reason)
      }
  }

  override def checkout(id: String): ServiceCall[NotUsed, String] = ServiceCall { _ =>
    entityRef(id)
      .ask(replyTo => Checkout(replyTo))
      .map {
        case Accepted(summary)  => asShoppingCartView(id, summary)
        case Rejected(reason)   => throw BadRequest(reason)
      }
  }

  private def asShoppingCartView(id: String, cart: Summary): String = {
    val items = cart.items.map {case (k, v) => s"$k=$v"}.mkString(":")
    val status = if (cart.checkedOut) "checkedout" else "open"
    s"$id:$items:$status"
  }

  override def getReport(cartId: String): ServiceCall[NotUsed, String] = ServiceCall { _ =>
    reportRepository.findById(cartId).map {
      case Some(cart) =>
      if (cart.checkedOut) "checkedout"
      else "open"
      case None => throw NotFound(s"Couldn't find a shopping cart report for '$cartId'")
    }
  }


} 
Example 18
Source File: Mass.scala    From fusion-data   with Apache License 2.0 5 votes vote down vote up
package mass

import akka.actor.typed.scaladsl.adapter._
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Props }
import akka.{ actor => classic }
import com.typesafe.config.Config
import fusion.common.config.FusionConfigFactory
import fusion.common.{ ReceptionistFactory, SpawnFactory }
import fusion.core.extension.FusionCore
import helloscala.common.Configuration
import mass.core.Constants

import scala.concurrent.ExecutionContext

final class Mass private (val classicSystem: classic.ActorSystem) extends SpawnFactory with ReceptionistFactory {
  implicit def executionContext: ExecutionContext = classicSystem.dispatcher

  val configuration: Configuration = FusionCore(classicSystem).configuration

  override def typedSystem: ActorSystem[_] = classicSystem.toTyped

  override def spawn[T](behavior: Behavior[T], props: Props): ActorRef[T] =
    classicSystem.spawnAnonymous(behavior, props)

  override def spawn[T](behavior: Behavior[T], name: String, props: Props): ActorRef[T] =
    classicSystem.spawn(behavior, name, props)
}

object Mass {
  def fromMergedConfig(config: Config): Mass =
    fromActorSystem(classic.ActorSystem(Constants.MASS, config))

  private[mass] def fromActorSystem(system: classic.ActorSystem): Mass = new Mass(system)

  def fromConfig(originalConfig: Config): Mass = {
    val config = FusionConfigFactory.arrangeConfig(originalConfig, Constants.MASS, Seq("akka"))
    fromMergedConfig(config)
  }
} 
Example 19
Source File: WordShuffler.scala    From streamee   with Apache License 2.0 5 votes vote down vote up
package io.moia.streamee.demo

import akka.actor.typed.{ ActorRef, Behavior }
import akka.actor.typed.scaladsl.Behaviors
import akka.stream.Materializer
import io.moia.streamee.{ IntoableProcessor, Process, ProcessSinkRef, Step }
import org.slf4j.LoggerFactory
import scala.annotation.tailrec
import scala.util.Random

object WordShuffler {

  final case class ShuffleWord(word: String)
  final case class WordShuffled(word: String)

  def apply(): Process[ShuffleWord, WordShuffled] =
    Process[ShuffleWord, WordShuffled]
      .via(shuffleWordToString)
      .via(shuffle)
      .via(stringToWordShuffled)

  def shuffleWordToString[Ctx]: Step[ShuffleWord, String, Ctx] =
    Step[ShuffleWord, Ctx].map(_.word)

  def shuffle[Ctx]: Step[String, String, Ctx] =
    Step[String, Ctx].map(shuffleWord)

  def stringToWordShuffled[Ctx]: Step[String, WordShuffled, Ctx] =
    Step[String, Ctx].map(WordShuffled)

  private def shuffleWord(word: String) = {
    @tailrec def loop(word: String, acc: String = ""): String =
      if (word.isEmpty)
        acc
      else {
        val (left, right) = word.splitAt(Random.nextInt(word.length))
        val c             = right.head
        val nextWord      = left + right.tail
        loop(nextWord, c +: acc)
      }

    if (word.length <= 3)
      word
    else
      word.head +: loop(word.tail.init) :+ word.last
  }
}

object WordShufflerRunner {
  import WordShuffler._

  sealed trait Command
  final case class GetProcessSinkRef(replyTo: ActorRef[ProcessSinkRef[ShuffleWord, WordShuffled]])
      extends Command
  final case object Shutdown     extends Command
  private final case object Stop extends Command

  private val logger = LoggerFactory.getLogger(getClass)

  def apply()(implicit mat: Materializer): Behavior[Command] =
    Behaviors.setup { context =>
      import context.executionContext

      val self                  = context.self
      val wordShufflerProcessor = IntoableProcessor(WordShuffler(), "word-shuffler")

      wordShufflerProcessor.whenDone.onComplete { reason =>
        if (logger.isWarnEnabled) logger.warn(s"Process completed: $reason")
        self ! Stop
      }

      Behaviors.receiveMessagePartial {
        case GetProcessSinkRef(replyTo) =>
          replyTo ! wordShufflerProcessor.sinkRef()
          Behaviors.same

        case Shutdown =>
          wordShufflerProcessor.shutdown()
          Behaviors.receiveMessagePartial { case Stop => Behaviors.stopped }
      }
    }
} 
Example 20
Source File: FromServer.scala    From korolev   with Apache License 2.0 5 votes vote down vote up
package korolev.data

import akka.actor.typed.ActorRef
import korolev.internal.Frontend
import ujson._

sealed trait FromServer

object FromServer {

  case class Procedure(procedure: Frontend.Procedure, args: List[Any]) extends FromServer

  object Procedure {

    def apply(code: Int, args: List[Any]): Procedure = {
      new Procedure(Frontend.Procedure(code).get, args)
    }

    def fromJson(ast: Value): Either[String, Procedure] =
      try {
        ast match {
          case arr: Arr =>
            val Num(procedureId) :: argsAsts = arr.value.toList
            val code = procedureId.toInt

            Frontend.Procedure(code) match {
              case Some(procedure) =>
                val args = argsAsts.collect {
                  case Str(s) => s
                  case Num(n) if n.toString.contains(".") => n.toDouble
                  case Num(n) => n.toInt
                  case False => false
                  case True => true
                  case Null => null
                }
                Right(FromServer.Procedure(procedure, args))
              case None => Left(s"unknown procedure #$code")
            }
          case other =>
            Left(s"Unexpected JSON #$other")
        }
      } catch {
        case e: MatchError =>
          Left(s"can't parse ast $e")
      }
  }

  case class ErrorOccurred(error: Error) extends FromServer

  case class Connected(ref: ActorRef[ToServer]) extends FromServer

  case object Closed extends FromServer

} 
Example 21
Source File: MusicCommands.scala    From AckCord   with MIT License 5 votes vote down vote up
package ackcord.examplecore.music

import ackcord._
import ackcord.commands.{CommandBuilder, CommandController, NamedCommand, VoiceGuildMemberCommandMessage}
import ackcord.data.{GuildId, TextChannel}
import ackcord.examplecore.music.MusicHandler.{NextTrack, QueueUrl, StopMusic, TogglePause}
import akka.NotUsed
import akka.actor.typed.scaladsl.AskPattern._
import akka.actor.typed.{ActorRef, ActorSystem}
import akka.stream.scaladsl.{Flow, Keep, Sink}
import akka.stream.typed.scaladsl.ActorFlow
import akka.util.Timeout

class MusicCommands(requests: Requests, guildId: GuildId, musicHandler: ActorRef[MusicHandler.Command])(
    implicit timeout: Timeout,
    system: ActorSystem[Nothing]
) extends CommandController(requests) {

  val VoiceCommand: CommandBuilder[VoiceGuildMemberCommandMessage, NotUsed] =
    GuildVoiceCommand.andThen(CommandBuilder.inOneGuild(guildId))

  val queue: NamedCommand[String] =
    VoiceCommand.named("&", Seq("q", "queue")).parsing[String].withSideEffects { m =>
      musicHandler.ask[MusicHandler.CommandAck.type](QueueUrl(m.parsed, m.textChannel, m.voiceChannel.id, _))
    }

  private def simpleCommand(
      aliases: Seq[String],
      mapper: (TextChannel, ActorRef[MusicHandler.CommandAck.type]) => MusicHandler.MusicHandlerEvents
  ): NamedCommand[NotUsed] = {
    VoiceCommand.andThen(CommandBuilder.inOneGuild(guildId)).named("&", aliases, mustMention = true).toSink {
      Flow[VoiceGuildMemberCommandMessage[NotUsed]]
        .map(_.textChannel)
        .via(ActorFlow.ask(requests.parallelism)(musicHandler)(mapper))
        .toMat(Sink.ignore)(Keep.none)
    }
  }

  val stop: NamedCommand[NotUsed] = simpleCommand(Seq("s", "stop"), StopMusic.apply)

  val next: NamedCommand[NotUsed] = simpleCommand(Seq("n", "next"), NextTrack.apply)

  val pause: NamedCommand[NotUsed] = simpleCommand(Seq("p", "pause"), TogglePause.apply)
} 
Example 22
Source File: WsHeart.scala    From AckCord   with MIT License 5 votes vote down vote up
package ackcord.voice

import scala.concurrent.duration._

import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler}
import akka.actor.typed.{ActorRef, Behavior}

object WsHeart {

  def apply(parent: ActorRef[VoiceWsHandler.Command]): Behavior[Command] =
    Behaviors.setup { ctx =>
      Behaviors.withTimers(timers => runningHeart(ctx, timers, parent, None, receivedAck = true))
    }

  def runningHeart(
      context: ActorContext[Command],
      timers: TimerScheduler[Command],
      parent: ActorRef[VoiceWsHandler.Command],
      previousNonce: Option[Int],
      receivedAck: Boolean
  ): Behavior[Command] = Behaviors.receiveMessage {
    case StartBeating(interval, nonce) =>
      context.log.debug(s"Starting to beat with initial nonce $nonce")
      timers.startTimerAtFixedRate("heartbeatTimerKey", Beat, interval.millis)
      runningHeart(context, timers, parent, Some(nonce), receivedAck = true)

    case StopBeating =>
      timers.cancel("heartbeatTimerKey")
      runningHeart(context, timers, parent, None, receivedAck = true)

    case BeatAck(nonce) =>
      val log = context.log
      log.debug(s"Received HeartbeatACK with nonce $nonce")
      if (previousNonce.contains(nonce))
        runningHeart(context, timers, parent, None, receivedAck = true)
      else {
        log.warn("Did not receive correct nonce in HeartbeatACK. Restarting.")
        parent ! VoiceWsHandler.Restart(fresh = false, 500.millis)
        Behaviors.same
      }
    case Beat =>
      val log = context.log
      if (receivedAck) {
        val nonce = System.currentTimeMillis().toInt

        parent ! VoiceWsHandler.SendHeartbeat(nonce)
        log.debug(s"Sent Heartbeat with nonce $nonce")

        runningHeart(context, timers, parent, previousNonce = Some(nonce), receivedAck = false)
      } else {
        log.warn("Did not receive HeartbeatACK between heartbeats. Restarting.")
        parent ! VoiceWsHandler.Restart(fresh = false, 0.millis)
        Behaviors.same
      }
  }

  sealed trait Command
  case class StartBeating(interval: Double, nonce: Int) extends Command
  case object StopBeating                               extends Command
  case class BeatAck(nonce: Int)                        extends Command
  case object Beat                                      extends Command
} 
Example 23
Source File: TFQueriesAkkaHttpResource.scala    From model-serving-tutorial   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.modelserving.tensorflowserving

import akka.actor.Scheduler
import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.AskPattern._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.util.Timeout
import com.lightbend.modelserving.model.ModelToServeStats
import de.heikoseeberger.akkahttpjackson.JacksonSupport

import scala.concurrent.duration._

object TFQueriesAkkaHttpResource extends JacksonSupport {

  implicit val askTimeout = Timeout(30.seconds)

  def storeRoutes(modelserver: ActorRef[TFModelServerActor])(implicit scheduler: Scheduler) : Route =
    get {
      // Get statistics
      path("state") {
        onSuccess(modelserver ? ((replyTo: ActorRef[ModelToServeStats]) => GetState(replyTo))) {
          case stats : ModelToServeStats =>
            complete(stats)
        }
      }
    }
} 
Example 24
Source File: TFServingModelServer.scala    From model-serving-tutorial   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.modelserving.tensorflowserving

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.scaladsl.adapter._
import akka.actor.typed.{ActorRef, ActorSystem}
import akka.http.scaladsl.Http
import akka.kafka.scaladsl.Consumer
import akka.kafka.{ConsumerSettings, Subscriptions}
import akka.stream.scaladsl.Sink
import akka.stream.typed.scaladsl.{ActorFlow, ActorMaterializer}
import akka.util.Timeout
import com.lightbend.modelserving.configuration.ModelServingConfiguration
import com.lightbend.modelserving.model.ServingResult
import com.lightbend.modelserving.winemodel.DataRecord
import org.apache.kafka.clients.consumer.ConsumerConfig
import org.apache.kafka.common.serialization.ByteArrayDeserializer

import scala.concurrent.duration._
import scala.util.Success


object TFServingModelServer {

  import ModelServingConfiguration._

  // Initialization

  implicit val modelServer = ActorSystem(
    Behaviors.setup[TFModelServerActor](
      context => new TFModelServerBehaviour(context)), "ModelServing")

  implicit val materializer = ActorMaterializer()
  implicit val executionContext = modelServer.executionContext
  implicit val askTimeout = Timeout(30.seconds)

  // Configuration properties for the Kafka topic.
  val dataSettings = ConsumerSettings(modelServer.toUntyped, new ByteArrayDeserializer, new ByteArrayDeserializer)
    .withBootstrapServers(KAFKA_BROKER)
    .withGroupId(DATA_GROUP)
    .withProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest")

  def main(args: Array[String]): Unit = {

    println(s"Akka application that uses TensorFlow Serving, brokers $KAFKA_BROKER")

    // Data stream processing
    Consumer.atMostOnceSource(dataSettings, Subscriptions.topics(DATA_TOPIC))
      .map(record => DataRecord.wineFromByteArray(record.value)).collect { case Success(a) => a }
      .via(ActorFlow.ask(1)(modelServer)((elem, replyTo : ActorRef[Option[ServingResult[Double]]]) => new ServeData(replyTo, elem)))
      .collect{ case Some(result) => result}
      .runWith(Sink.foreach(result =>
        println(s"Model served in ${System.currentTimeMillis() - result.submissionTs} ms, with result ${result.result} " +
          s"(model ${result.name}, data type ${result.dataType})")))
    // Rest Server
    startRest(modelServer)
  }

  def startRest(modelServerManager: ActorSystem[TFModelServerActor]): Unit = {

    implicit val timeout = Timeout(10.seconds)
    implicit val system = modelServerManager.toUntyped

    val host = "0.0.0.0"
    val port = MODELSERVING_PORT
    val routes = TFQueriesAkkaHttpResource.storeRoutes(modelServerManager)(modelServerManager.scheduler)

    val _ = Http().bindAndHandle(routes, host, port) map
      { binding =>
        println(s"Starting models observer on port ${binding.localAddress}") } recover {
      case ex =>
        println(s"Models observer could not bind to $host:$port - ${ex.getMessage}")
    }
  }
} 
Example 25
Source File: TypedMessages.scala    From model-serving-tutorial   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.modelserving.akka

import akka.Done
import akka.actor.typed.ActorRef
import com.lightbend.model.winerecord.WineRecord
import com.lightbend.modelserving.model.{DataToServe, ModelToServe, ModelToServeStats, ServingResult}

// Controller
trait ModelServerActor
case class UpdateModel(reply: ActorRef[Done], model : ModelToServe) extends ModelServerActor with ModelServerManagerActor
case class ScoreData(reply: ActorRef[Option[ServingResult[Double]]], record : DataToServe[WineRecord]) extends ModelServerActor with ModelServerManagerActor
case class GetState(reply: ActorRef[ModelToServeStats], dataType : String) extends ModelServerActor with ModelServerManagerActor

// Controller manager
trait ModelServerManagerActor
case class GetModels(reply: ActorRef[GetModelsResult]) extends ModelServerManagerActor

// Reply messages
case class GetModelsResult(models : Seq[String]) 
Example 26
Source File: QueriesAkkaHttpResource.scala    From model-serving-tutorial   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.modelserving.akka

import akka.actor.Scheduler
import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.AskPattern._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.util.Timeout
import com.lightbend.modelserving.model.ModelToServeStats
import de.heikoseeberger.akkahttpjackson.JacksonSupport

import scala.concurrent.duration._

object QueriesAkkaHttpResource extends JacksonSupport {

  implicit val askTimeout = Timeout(30.seconds)

  def storeRoutes(modelserver: ActorRef[ModelServerManagerActor])(implicit scheduler: Scheduler) : Route =
    get {
      // Get list of models
      path("processors") {
        onSuccess(modelserver ? ((replyTo: ActorRef[GetModelsResult]) => GetModels(replyTo))) {
          case models: GetModelsResult =>
            complete(models)
        }
      } ~
      // Get statistics for a given data type
      path("state"/Segment) { dataType =>
        onSuccess(modelserver ? ((replyTo: ActorRef[ModelToServeStats]) => GetState(replyTo, dataType))) {
          case stats : ModelToServeStats =>
            complete(stats)
        }
      }
    }
} 
Example 27
Source File: ModelServerManagerBehavior.scala    From model-serving-tutorial   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.modelserving.akka

import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior}
import com.lightbend.modelserving.model.ModelToServeStats


class ModelServerManagerBehavior(context: ActorContext[ModelServerManagerActor]) extends AbstractBehavior[ModelServerManagerActor] {

  println("Creating Model Serving Manager")

  private def getModelServer(dataType: String): ActorRef[ModelServerActor] = {

    context.child(dataType) match {
      case Some(actorRef) => actorRef.asInstanceOf[ActorRef[ModelServerActor]]
      case _ => context.spawn(Behaviors.setup[ModelServerActor](
        context => new ModelServerBehavior(context, dataType)), dataType)
    }
  }

  private def getInstances : GetModelsResult = GetModelsResult(context.children.map(_.path.name).toSeq)

  override def onMessage(msg: ModelServerManagerActor): Behavior[ModelServerManagerActor] = {
    msg match {
      case updateModel : UpdateModel =>
        getModelServer(updateModel.model.dataType) tell updateModel
      case scoreData : ScoreData =>
        getModelServer(scoreData.record.getType) tell scoreData
      case getState : GetState => // Used for state queries
        context.child(getState.dataType) match{
        case Some(server) => server.asInstanceOf[ActorRef[ModelServerActor]] tell getState
        case _ => getState.reply ! ModelToServeStats()
      }
      case getModels : GetModels => // Get list of models
        getModels.reply ! getInstances
    }
    this
  }
} 
Example 28
Source File: UserView.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import akka.actor.typed.scaladsl.Actor
import akka.actor.typed.{ ActorRef, Behavior }
import akka.cluster.ddata.ORSet
import akka.cluster.ddata.typed.scaladsl.{ DistributedData, Replicator }
import org.apache.logging.log4j.scala.Logging

object UserView extends Logging {

  sealed trait Command

  final case class GetUsers(replyTo: ActorRef[Users]) extends Command
  final case class Users(users: Set[User])

  private final case class UsersChanged(users: Set[User]) extends Command

  final val Name = "user-view"

  def apply(users: Set[User] = Set.empty): Behavior[Command] =
    Actor.deferred { context =>
      val changedAdapter =
        context.spawnAdapter { (changed: Replicator.Changed[ORSet[User]]) =>
          UsersChanged(changed.dataValue.elements)
        }
      val replicator = DistributedData(context.system).replicator
      replicator ! Replicator.Subscribe(UserProjection.usersKey, changedAdapter)

      Actor.immutable {
        case (_, GetUsers(replyTo)) =>
          replyTo ! Users(users)
          Actor.same

        case (_, UsersChanged(users)) =>
          UserView(users)
      }
    }
} 
Example 29
Source File: UserRepositorySerializer.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import akka.actor.ExtendedActorSystem
import akka.actor.typed.{ ActorRef, ActorRefResolver }
import akka.serialization.SerializerWithStringManifest
import de.heikoseeberger.wtat.proto.userrepository.{
  AddUser => AddUserProto,
  RemoveUser => RemoveUserProto,
  UserAdded => UserAddedProto,
  UserRemoved => UserRemovedProto,
  UsernameTaken => UsernameTakenProto,
  UsernameUnknown => UsernameUnknownProto
}
import de.heikoseeberger.wtat.proto.{ User => UserProto }
import java.io.NotSerializableException

final class UserRepositorySerializer(system: ExtendedActorSystem)
    extends SerializerWithStringManifest {
  import UserRepository._
  import akka.actor.typed.scaladsl.adapter._

  override val identifier = 4243

  private final val AddUserManifest         = "AddUser"
  private final val UsernameTakenManifest   = "UsernameTaken"
  private final val UserAddedManifest       = "UserAdded"
  private final val RemoveUserManifest      = "RemoveUser"
  private final val UsernameUnknownManifest = "UsernameUnknown"
  private final val UserRemovedManifest     = "UserRemoved"

  private val resolver = ActorRefResolver(system.toTyped)

  override def manifest(o: AnyRef) =
    o match {
      case serializable: Serializable =>
        serializable match {
          case _: AddUser         => AddUserManifest
          case _: UsernameTaken   => UsernameTakenManifest
          case _: UserAdded       => UserAddedManifest
          case _: RemoveUser      => RemoveUserManifest
          case _: UsernameUnknown => UsernameUnknownManifest
          case _: UserRemoved     => UserRemovedManifest
        }
      case _ => throw new IllegalArgumentException(s"Unknown class: ${o.getClass}!")
    }

  override def toBinary(o: AnyRef) = {
    def userProto(user: User)      = UserProto(user.username.value, user.nickname.value)
    def toBinary(ref: ActorRef[_]) = resolver.toSerializationFormat(ref)
    val proto =
      o match {
        case serializable: Serializable =>
          serializable match {
            case AddUser(user, replyTo)        => AddUserProto(Some(userProto(user)), toBinary(replyTo))
            case UsernameTaken(username)       => UsernameTakenProto(username)
            case UserAdded(user)               => UserAddedProto(Some(userProto(user)))
            case RemoveUser(username, replyTo) => RemoveUserProto(username, toBinary(replyTo))
            case UsernameUnknown(username)     => UsernameUnknownProto(username)
            case UserRemoved(username)         => UserRemovedProto(username)
          }
        case _ => throw new IllegalArgumentException(s"Unknown class: ${o.getClass}!")
      }
    proto.toByteArray
  }

  override def fromBinary(bytes: Array[Byte], manifest: String) = {
    def addUser(proto: AddUserProto)                 = AddUser(user(proto.user.get), fromBinary(proto.replyTo))
    def usernameTaken(proto: UsernameTakenProto)     = UsernameTaken(proto.username)
    def userAdded(proto: UserAddedProto)             = UserAdded(user(proto.user.get))
    def user(proto: UserProto)                       = User(proto.username, proto.nickname).valueOr(_.fail)
    def removeUser(proto: RemoveUserProto)           = RemoveUser(proto.username, fromBinary(proto.replyTo))
    def usernameUnknown(proto: UsernameUnknownProto) = UsernameUnknown(proto.username)
    def userRemoved(proto: UserRemovedProto)         = UserRemoved(proto.username)
    def fromBinary(ref: String)                      = resolver.resolveActorRef(ref)
    manifest match {
      case AddUserManifest         => addUser(AddUserProto.parseFrom(bytes))
      case UsernameTakenManifest   => usernameTaken(UsernameTakenProto.parseFrom(bytes))
      case UserAddedManifest       => userAdded(UserAddedProto.parseFrom(bytes))
      case RemoveUserManifest      => removeUser(RemoveUserProto.parseFrom(bytes))
      case UsernameUnknownManifest => usernameUnknown(UsernameUnknownProto.parseFrom(bytes))
      case UserRemovedManifest     => userRemoved(UserRemovedProto.parseFrom(bytes))
      case _                       => throw new NotSerializableException(s"Unknown manifest: $manifest!")
    }
  }
} 
Example 30
Source File: UserRepository.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import akka.actor.typed.{ ActorRef, Behavior }
import akka.persistence.typed.scaladsl.PersistentActor
import akka.persistence.typed.scaladsl.PersistentActor.{ CommandHandler, Effect }
import eu.timepit.refined.api.Refined
import java.io.{ Serializable => JavaSerializable }
import org.apache.logging.log4j.scala.Logging

object UserRepository extends Logging {

  sealed trait Serializable extends JavaSerializable

  sealed trait Command
  sealed trait Event

  final case class AddUser(user: User, replyTo: ActorRef[AddUserReply])
      extends Command
      with Serializable
  sealed trait AddUserReply
  final case class UsernameTaken(username: String) extends AddUserReply with Serializable
  final case class UserAdded(user: User)           extends AddUserReply with Event with Serializable

  final case class RemoveUser(username: String, replyTo: ActorRef[RemoveUserReply])
      extends Command
      with Serializable
  sealed trait RemoveUserReply
  final case class UsernameUnknown(username: String) extends RemoveUserReply with Serializable
  final case class UserRemoved(username: String)
      extends RemoveUserReply
      with Event
      with Serializable

  final case object Stop extends Command

  final case class State(usernames: Set[String] = Set.empty)

  final val Name = "user-repository"

  def apply(): Behavior[Command] =
    PersistentActor.immutable(Name, State(), commandHandler, eventHandler)

  def addUser(user: User)(replyTo: ActorRef[AddUserReply]): AddUser =
    AddUser(user, replyTo)

  def removeUser(username: String)(replyTo: ActorRef[RemoveUserReply]): RemoveUser =
    RemoveUser(username, replyTo)

  private def commandHandler =
    CommandHandler[Command, Event, State] {
      case (_, State(usernames), AddUser(user @ User(Refined(username), _), replyTo)) =>
        if (usernames.contains(username)) {
          logger.info(s"Username $username taken")
          replyTo ! UsernameTaken(username)
          Effect.none
        } else {
          val userAdded = UserAdded(user)
          Effect
            .persist(userAdded)
            .andThen { _ =>
              logger.info(s"User with username $username added")
              replyTo ! userAdded
            }
        }

      case (_, State(usernames), RemoveUser(username, replyTo)) =>
        if (!usernames.contains(username)) {
          logger.info(s"Username $username unknown")
          replyTo ! UsernameUnknown(username)
          Effect.none
        } else {
          val userRemoved = UserRemoved(username)
          Effect
            .persist(userRemoved)
            .andThen { _ =>
              logger.info(s"User with username $username removed")
              replyTo ! userRemoved
            }
        }

      case (_, _, Stop) =>
        Effect.stop
    }

  private def eventHandler(state: State, event: Event) =
    event match {
      case UserAdded(user)       => state.copy(state.usernames + user.username.value)
      case UserRemoved(username) => state.copy(state.usernames - username)
    }
} 
Example 31
Source File: UserProjection.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import akka.actor.Scheduler
import akka.actor.typed.{ ActorRef, Behavior }
import akka.actor.typed.scaladsl.Actor
import akka.actor.typed.scaladsl.AskPattern.Askable
import akka.cluster.Cluster
import akka.cluster.ddata.{ ORSet, ORSetKey }
import akka.cluster.ddata.Replicator.WriteLocal
import akka.cluster.ddata.typed.scaladsl.{ DistributedData, Replicator }
import akka.persistence.query.EventEnvelope
import akka.persistence.query.scaladsl.EventsByPersistenceIdQuery
import akka.stream.Materializer
import akka.stream.scaladsl.Sink
import akka.util.Timeout
import cats.instances.string._
import cats.syntax.eq._
import org.apache.logging.log4j.scala.Logging
import scala.concurrent.duration.FiniteDuration

object UserProjection extends Logging {
  import akka.actor.typed.scaladsl.adapter._

  sealed trait Command
  final case object Stop                              extends Command
  private final case object HandleEventStreamComplete extends Command

  abstract class EventStreamCompleteException
      extends IllegalStateException("Event stream completed unexpectedly!")
  private final case object EventStreamCompleteException extends EventStreamCompleteException

  final val Name = "user-projection"

  final val usersKey: ORSetKey[User] =
    ORSetKey("users")

  def apply(readJournal: EventsByPersistenceIdQuery,
            userView: ActorRef[UserView.Command],
            askTimeout: FiniteDuration)(implicit mat: Materializer): Behavior[Command] =
    Actor.deferred { context =>
      implicit val c: Cluster   = Cluster(context.system.toUntyped)
      implicit val s: Scheduler = context.system.scheduler
      implicit val t: Timeout   = askTimeout
      val replicator            = DistributedData(context.system).replicator
      val self                  = context.self

      readJournal
        .eventsByPersistenceId(UserRepository.Name, 0, Long.MaxValue)
        .collect { case EventEnvelope(_, _, _, event: UserRepository.Event) => event }
        .mapAsync(1) {
          case UserRepository.UserAdded(user) =>
            replicator ? Replicator.Update(usersKey, ORSet.empty[User], WriteLocal)(_ + user)

          case UserRepository.UserRemoved(username) =>
            replicator ? Replicator.Update(usersKey, ORSet.empty[User], WriteLocal) { users =>
              users.elements.find(_.username.value === username).fold(users)(users - _)
            }
        }
        .runWith(Sink.onComplete(_ => self ! HandleEventStreamComplete))
      logger.debug("Running event stream")

      Actor.immutable {
        case (_, Stop)                      => Actor.stopped
        case (_, HandleEventStreamComplete) => throw EventStreamCompleteException
      }
    }
} 
Example 32
Source File: Api.scala    From whirlwind-tour-akka-typed   with Apache License 2.0 5 votes vote down vote up
package de.heikoseeberger.wtat

import akka.actor.{ ActorSystem, Scheduler }
import akka.http.scaladsl.Http
import akka.http.scaladsl.Http.ServerBinding
import akka.http.scaladsl.model.StatusCodes.{ Conflict, Created, NoContent, NotFound }
import akka.http.scaladsl.server.{ Directives, Route }
import akka.stream.Materializer
import akka.actor.typed.scaladsl.Actor
import akka.actor.typed.scaladsl.AskPattern.Askable
import akka.actor.typed.{ ActorRef, Behavior }
import akka.util.Timeout
import de.heikoseeberger.akkahttpcirce.ErrorAccumulatingCirceSupport
import java.net.InetSocketAddress
import org.apache.logging.log4j.scala.Logging
import scala.concurrent.duration.FiniteDuration
import scala.util.{ Failure, Success }

object Api extends Logging {

  sealed trait Command
  private final case object HandleBindFailure                      extends Command
  private final case class HandleBound(address: InetSocketAddress) extends Command

  final val Name = "api"

  def apply(address: String,
            port: Int,
            userRepository: ActorRef[UserRepository.Command],
            userView: ActorRef[UserView.Command],
            askTimeout: FiniteDuration)(implicit mat: Materializer): Behavior[Command] =
    Actor.deferred { context =>
      import akka.actor.typed.scaladsl.adapter._
      import context.executionContext
      implicit val s: ActorSystem = context.system.toUntyped

      val self = context.self
      Http()
        .bindAndHandle(route(userRepository, userView)(askTimeout, context.system.scheduler),
                       address,
                       port)
        .onComplete {
          case Failure(_)                      => self ! HandleBindFailure
          case Success(ServerBinding(address)) => self ! HandleBound(address)
        }

      Actor.immutable {
        case (_, HandleBindFailure) =>
          logger.error(s"Stopping, because cannot bind to $address:$port!")
          Actor.stopped

        case (_, HandleBound(address)) =>
          logger.info(s"Bound to $address")
          Actor.ignore
      }
    }

  def route(
      userRepository: ActorRef[UserRepository.Command],
      userView: ActorRef[UserView.Command]
  )(implicit askTimeout: Timeout, scheduler: Scheduler): Route = {
    import Directives._
    import ErrorAccumulatingCirceSupport._
    import io.circe.generic.auto._
    import io.circe.refined._

    pathEndOrSingleSlash {
      get {
        complete {
          import UserView._
          (userView ? GetUsers).mapTo[Users]
        }
      } ~
      post {
        entity(as[User]) { user =>
          import UserRepository._
          onSuccess(userRepository ? addUser(user)) {
            case UsernameTaken(_) => complete(Conflict)
            case UserAdded(_)     => complete(Created)
          }
        }
      }
    } ~
    path(Segment) { username =>
      delete {
        import UserRepository._
        onSuccess(userRepository ? removeUser(username)) {
          case UsernameUnknown(_) => complete(NotFound)
          case UserRemoved(_)     => complete(NoContent)
        }
      }
    }
  }
} 
Example 33
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 34
Source File: WsOrderBookState.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.api.ws.state

import akka.actor.typed.ActorRef
import cats.syntax.option._
import com.wavesplatform.dex.api.ws.entities.{WsLastTrade, WsOrderBookSettings}
import com.wavesplatform.dex.api.ws.protocol
import com.wavesplatform.dex.api.ws.protocol.WsOrderBookChanges
import com.wavesplatform.dex.api.ws.state.WsAddressState.getNextUpdateId
import com.wavesplatform.dex.domain.asset.AssetPair
import com.wavesplatform.dex.domain.model.Denormalization.{denormalizeAmountAndFee, denormalizePrice}
import com.wavesplatform.dex.domain.model.{Amount, Price}
import com.wavesplatform.dex.model.{LastTrade, LevelAmounts}
import monocle.macros.GenLens

import scala.collection.immutable.TreeMap

case class WsOrderBookState(wsConnections: Map[ActorRef[WsOrderBookChanges], Long],
                            changedAsks: Set[Price],
                            changedBids: Set[Price],
                            lastTrade: Option[LastTrade],
                            changedTickSize: Option[Double]) {

  val genLens: GenLens[WsOrderBookState] = GenLens[WsOrderBookState]

  def addSubscription(x: ActorRef[WsOrderBookChanges]): WsOrderBookState = copy(wsConnections = wsConnections.updated(x, 0L))

  def withoutSubscription(x: ActorRef[WsOrderBookChanges]): WsOrderBookState =
    if (wsConnections.size == 1) WsOrderBookState(Map.empty, Set.empty, Set.empty, None, None)
    else copy(wsConnections = wsConnections - x)

  def hasSubscriptions: Boolean = wsConnections.nonEmpty

  def hasChanges: Boolean = changedAsks.nonEmpty || changedBids.nonEmpty || lastTrade.nonEmpty || changedTickSize.nonEmpty

  def denormalized(amountDecimals: Int, priceDecimals: Int, xs: TreeMap[Price, Amount]): TreeMap[Double, Double] = xs.map {
    case (price, amount) =>
      denormalizePrice(price, amountDecimals, priceDecimals).toDouble -> denormalizeAmountAndFee(amount, amountDecimals).toDouble
  }

  def lastTrade(amountDecimals: Int, priceDecimals: Int, x: LastTrade): WsLastTrade = WsLastTrade(
    price = denormalizePrice(x.price, amountDecimals, priceDecimals).toDouble,
    amount = denormalizeAmountAndFee(x.amount, amountDecimals).toDouble,
    side = x.side
  )

  def flushed(assetPair: AssetPair,
              amountDecimals: Int,
              priceDecimals: Int,
              asks: TreeMap[Price, Amount],
              bids: TreeMap[Price, Amount],
              timestamp: Long): WsOrderBookState = copy(
    wsConnections = if (hasChanges) {
      val changes =
        protocol.WsOrderBookChanges(
          assetPair = assetPair,
          asks = denormalized(amountDecimals, priceDecimals, take(asks, changedAsks)),
          bids = denormalized(amountDecimals, priceDecimals, take(bids, changedBids)),
          lastTrade = lastTrade.map(lastTrade(amountDecimals, priceDecimals, _)),
          updateId = 0L, // Will be changed below
          timestamp = timestamp,
          settings = if (changedTickSize.isDefined) WsOrderBookSettings(None, changedTickSize).some else None
        )
      wsConnections.map {
        case (conn, updateId) =>
          val newUpdateId = getNextUpdateId(updateId)
          conn ! changes.copy(updateId = newUpdateId)
          conn -> newUpdateId
      }
    } else wsConnections,
    changedAsks = Set.empty,
    changedBids = Set.empty,
    lastTrade = None,
    changedTickSize = None
  )

  def take(xs: TreeMap[Price, Amount], levels: Set[Price]): TreeMap[Price, Amount] = {
    // 1. Levels will be always smaller, than xs
    // 2. A level could gone from xs
    val r = TreeMap.newBuilder[Price, Amount](xs.ordering)
    levels.foreach { level =>
      r += level -> xs.getOrElse(level, 0L)
    }
    r.result()
  }

  def accumulateChanges(lc: LevelAmounts, lt: Option[LastTrade], ts: Option[Double]): WsOrderBookState =
    if (hasSubscriptions) {
      (
        genLens(_.changedAsks).modify(_ ++ lc.asks.keySet) andThen
          genLens(_.changedBids).modify(_ ++ lc.bids.keySet) andThen
          genLens(_.lastTrade).modify { if (lt.isEmpty) _ else lt } andThen
          genLens(_.changedTickSize).modify { if (ts.isEmpty) _ else ts }
      )(this)
    } else this
} 
Example 35
Source File: Bus.scala    From lila-ws   with GNU Affero General Public License v3.0 5 votes vote down vote up
package lila.ws

import akka.actor.typed.ActorRef

import ipc.ClientMsg

object Bus {

  type Chan = String

  private val impl = new util.EventBus[ClientMsg, Chan, ActorRef[ClientMsg]](
    initialCapacity = 65535,
    publish = (actor, event) => actor ! event
  )

  def subscribe   = impl.subscribe _
  def unsubscribe = impl.unsubscribe _

  def publish(chan: Chan, event: ClientMsg): Unit =
    impl.publish(chan, event)

  def publish(chan: ChanSelect, event: ClientMsg): Unit =
    impl.publish(chan(channel), event)

  def publish(msg: Msg): Unit =
    impl.publish(msg.channel, msg.event)

  case class Msg(event: ClientMsg, channel: Chan)

  type ChanSelect = Bus.channel.type => Chan

  object channel {
    def sri(s: Sri)               = s"sri/${s.value}"
    def flag(f: Flag)             = s"flag/$f"
    val mlat                      = "mlat"
    val all                       = "all"
    val lobby                     = "lobby"
    val tv                        = "tv"
    def userTv(userId: User.ID)   = s"userTv/$userId"
    def room(id: RoomId)          = s"room/$id"
    def tourStanding(id: Tour.ID) = s"tour-standing/$id"
    def externalChat(id: RoomId)  = s"external-chat/$id"
  }

  def msg(event: ClientMsg, chan: ChanSelect) =
    Msg(event, chan(channel))

  def size                     = impl.size
  def sizeOf(chan: ChanSelect) = impl sizeOf chan(channel)

  // distinct bus for internal events
  val internal = new util.EventBus[Any, Chan, PartialFunction[Any, Unit]](
    initialCapacity = 16,
    publish = (listener, event) => listener lift event
  )
} 
Example 36
Source File: Fens.scala    From lila-ws   with GNU Affero General Public License v3.0 5 votes vote down vote up
package lila.ws

import akka.actor.typed.ActorRef
import chess.format.{ FEN, Uci }
import java.util.concurrent.ConcurrentHashMap

import ipc._


object Fens {

  case class Position(lastUci: Uci, fen: FEN)
  case class Watched(position: Option[Position], clients: Set[ActorRef[ClientMsg]])

  private val games = new ConcurrentHashMap[Game.Id, Watched](1024)

  // client starts watching
  def watch(gameIds: Iterable[Game.Id], client: Client): Unit =
    gameIds foreach { gameId =>
      games
        .compute(
          gameId,
          {
            case (_, null)                  => Watched(None, Set(client))
            case (_, Watched(pos, clients)) => Watched(pos, clients + client)
          }
        )
        .position foreach {
        case Position(lastUci, fen) => client ! ClientIn.Fen(gameId, lastUci, fen)
      }
    }

  // when a client disconnects
  def unwatch(gameIds: Iterable[Game.Id], client: Client): Unit =
    gameIds foreach { gameId =>
      games.computeIfPresent(
        gameId,
        (_, watched) => {
          val newClients = watched.clients - client
          if (newClients.isEmpty) null
          else watched.copy(clients = newClients)
        }
      )
    }

  // move coming from the server
  def move(gameId: Game.Id, json: JsonString): Unit = {
    games.computeIfPresent(
      gameId,
      (_, watched) =>
        json.value match {
          case MoveRegex(uciS, fenS) =>
            Uci(uciS).fold(watched) { lastUci =>
              val fen = FEN(fenS)
              val msg = ClientIn.Fen(gameId, lastUci, fen)
              watched.clients foreach { _ ! msg }
              watched.copy(position = Some(Position(lastUci, fen)))
            }
          case _ => watched
        }
    )
  }

  // ...,"uci":"h2g2","san":"Rg2","fen":"r2qb1k1/p2nbrpn/6Np/3pPp1P/1ppP1P2/2P1B3/PP2B1R1/R2Q1NK1",...
  private val MoveRegex = """uci":"([^"]+)".+fen":"([^"]+)""".r.unanchored

  def size = games.size
} 
Example 37
Source File: package.scala    From lila-ws   with GNU Affero General Public License v3.0 5 votes vote down vote up
package lila

import akka.actor.typed.{ ActorRef, ActorSystem, Behavior }

package object ws {

  type Emit[A] = Function[A, Unit]

  type ClientSystem   = ActorSystem[Clients.Control]
  type ClientBehavior = Behavior[ipc.ClientMsg]
  type Client         = ActorRef[ipc.ClientMsg]
  type ClientEmit     = Emit[ipc.ClientIn]

  type ~[+A, +B] = Tuple2[A, B]
  object ~ {
    def apply[A, B](x: A, y: B)                              = Tuple2(x, y)
    def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x)
  }

  @inline implicit def toOrnicarAddKcombinator[A](any: A) =
    new ornicarAddKcombinator(any)
}

final class ornicarAddKcombinator[A](private val any: A) extends AnyVal {
  def kCombinator(sideEffect: A => Unit): A = {
    sideEffect(any)
    any
  }
  def ~(sideEffect: A => Unit): A = kCombinator(sideEffect)
  def pp: A                       = kCombinator(println)
  def pp(msg: String): A          = kCombinator(a => println(s"[$msg] $a"))
} 
Example 38
Source File: CustomCache.scala    From akka_streams_tutorial   with MIT License 5 votes vote down vote up
package sample.stream_actor.typed

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}

case class DeviceId(id: String)

object CustomCache {
  sealed trait CacheRequests
  final case class Get(requestId: String, replyTo: ActorRef[CacheResponses]) extends CacheRequests
  final case class Devices(devices: List[DeviceId])                          extends CacheRequests
  final case class AddDevices(devices: List[DeviceId])                       extends CacheRequests

  sealed trait CacheResponses
  final case object EmptyCache                            extends CacheResponses
  final case class CachedDevices(devices: List[DeviceId]) extends CacheResponses

  val empty: Behavior[CacheRequests] =
    Behaviors.receive[CacheRequests] { (context, message) =>
      message match {
        case Get(requestId, replyTo) =>
          context.log.info("Empty cache request for requestId {}.", requestId)
          replyTo ! EmptyCache
          Behaviors.same
        case Devices(devices) =>
          context.log.info(s"Initializing cache with: ${devices.size} devices")
          cached(devices)
        case AddDevices(devices) =>
          context.log.info(s"Initializing cache with: ${devices.size} devices")
          cached(devices)
      }
    }

  private def cached(devices: List[DeviceId]): Behavior[CacheRequests] =
    Behaviors.receive { (context, message) =>
      message match {
        case Get(requestId, replyTo) =>
          context.log.info("Cache request for requestId {}.", requestId)
          replyTo ! CachedDevices(devices)
          Behaviors.same
        case Devices(updatedDevices) =>
          context.log.info(s"Updating cache with: ${updatedDevices.size} devices")
          cached(updatedDevices)
        case AddDevices(updatedDevices) =>
          context.log.info(s"Adding: ${updatedDevices.size} devices.")
          cached(devices = devices ++ updatedDevices)
      }
    }
} 
Example 39
Source File: Boy.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12

import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.Behaviors
import ch12.Shop._

object Boy {
  final case class GoShopping(shoppingList: ShoppingList,
                              seller: ActorRef[SellByList],
                              manager: ActorRef[Manager.Command])

  val goShopping = Behaviors.receiveMessage[GoShopping] {
    case GoShopping(shoppingList, seller, manager) =>
      seller ! SellByList(shoppingList, manager)
      Behaviors.stopped
  }
} 
Example 40
Source File: Baker.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12
import akka.actor.typed.{ActorRef, Behavior}
import akka.actor.typed.scaladsl.{Behaviors, StashBuffer}
import ch12.Bakery.{RawCookies, ReadyCookies}
import ch12.Manager.ReceiveReadyCookies
import ch12.Oven.{Extract, Put}

import scala.concurrent.duration._

object Baker {
  val DefaultBakingTime: FiniteDuration = 2.seconds
  private val TimerKey = 'TimerKey
  sealed trait Command
  final case class BakeCookies(raw: RawCookies,
                               sender: ActorRef[Manager.Command])
      extends Command
  final case class TooManyCookies(raw: RawCookies) extends Command
  final case class CookiesReady(cookies: ReadyCookies) extends Command
  final case object CheckOven extends Command

  def turnOvenOn: Behavior[Command] = Behaviors.setup { context =>
    val oven = context.spawn(Oven.empty, "Oven")
    idle(oven)
  }

  def idle(oven: ActorRef[Oven.Command]): Behavior[Command] =
    Behaviors.receivePartial {
      case (context, BakeCookies(rawCookies, manager)) =>
        oven ! Put(rawCookies.count, context.self)
        Behaviors.withTimers { timers =>
          timers.startSingleTimer(TimerKey, CheckOven, DefaultBakingTime)
          baking(oven, manager)
        }
    }

  def baking(oven: ActorRef[Oven.Command],
             manager: ActorRef[Manager.Command]): Behavior[Command] =
    Behaviors.setup[Command] { context =>
      val buffer = StashBuffer[Command](capacity = 100)

      Behaviors.receiveMessage {
        case CheckOven =>
          oven ! Extract(context.self)
          Behaviors.same
        case CookiesReady(cookies) =>
          manager ! ReceiveReadyCookies(cookies)
          buffer.unstashAll(context, idle(oven))
        case c: TooManyCookies=>
          buffer.stash(BakeCookies(c.raw, manager))
          Behaviors.same
        case c : BakeCookies =>
          buffer.stash(c)
          Behaviors.same
      }
    }
} 
Example 41
Source File: Chef.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior, DispatcherSelector}
import ch12.Bakery.{Groceries, Dough}
import ch12.Manager.ReceiveDough

object Chef {

  sealed trait Command

  final case class Mix(g: Groceries, manager: ActorRef[Manager.Command])
    extends Command

  final case class Collect(p: Dough, mixer: ActorRef[Mixer.Mix])
    extends Command

  final case class BrokenMixer(mixer: ActorRef[Mixer.Mix]) extends Command

  def idle(mixerFactory: Behavior[Mixer.Mix]): Behaviors.Receive[Command] =
    Behaviors.receivePartial[Command] {
      case (context,
      mix@Mix(Groceries(eggs, flour, sugar, chocolate), manager)) =>
        val mixers = for (i <- 1 to eggs)
          yield
            context.spawn(mixerFactory,
              s"Mixer_$i",
              DispatcherSelector.fromConfig("mixers-dispatcher"))
        mixers.foreach(mixer => context.watchWith(mixer, BrokenMixer(mixer)))
        val msg = Groceries(1, flour / eggs, sugar / eggs, chocolate / eggs)
        mixers.foreach(_ ! Mixer.Mix(msg, context.self))
        mixing(mixers.toSet, 0, manager, mixerFactory)
    }

  def mixing(mixers: Set[ActorRef[Mixer.Mix]],
             collected: Int,
             manager: ActorRef[Manager.Command],
             mixerBuilder: Behavior[Mixer.Mix]): Behaviors.Receive[Command] = {

    def designateBehavior(mixer: ActorRef[Mixer.Mix], doughBuf: Int) = {
      val mixersToGo = mixers - mixer
      if (mixersToGo.isEmpty) {
        manager ! ReceiveDough(Dough(doughBuf))
        idle(mixerBuilder)
      } else {
        mixing(mixersToGo, doughBuf, manager, mixerBuilder)
      }
    }

    Behaviors.receivePartial {
      case (context, Collect(dough, mixer)) =>
        val doughBuf = collected + dough.weight
        context.stop(mixer)
        designateBehavior(mixer, doughBuf)
      case (context, BrokenMixer(m)) =>
        context.log.warning("Broken mixer detected {}", m)
        context.self ! Collect(Dough(0), m)
        designateBehavior(m, collected)
    }
  }

} 
Example 42
Source File: Mixer.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12

import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
import akka.actor.typed.scaladsl.Behaviors
import ch12.Bakery.{Groceries, Dough}
import ch12.Chef.Collect

import scala.concurrent.duration.FiniteDuration
import scala.util.Random

object Mixer {
  class MotorOverheatException extends Exception
  class SlowRotationSpeedException extends Exception
  class StrongVibrationException extends Exception

  final case class Mix(groceries: Groceries, sender: ActorRef[Collect])

  def mix(mixTime: FiniteDuration): Behavior[Mix] = Behaviors.receive[Mix] {
    case (ctx, Mix(Groceries(eggs, flour, sugar, chocolate), sender)) =>
      if (Random.nextBoolean()) throw new MotorOverheatException
      Thread.sleep(mixTime.toMillis)
      sender ! Collect(Dough(eggs * 50 + flour + sugar + chocolate), ctx.self)
      Behaviors.stopped
  }

  def controlledMix(mixTime: FiniteDuration): Behavior[Mix] =
    Behaviors
      .supervise(
        Behaviors
          .supervise(Behaviors
            .supervise(mix(mixTime))
            .onFailure[MotorOverheatException](SupervisorStrategy.stop))
          .onFailure[SlowRotationSpeedException](SupervisorStrategy.restart))
      .onFailure[StrongVibrationException](SupervisorStrategy.resume)
} 
Example 43
Source File: Cook.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12

import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.Behaviors
import ch12.Bakery.{Dough, RawCookies}
import ch12.Manager.ReceiveRawCookies

object Cook {
  final case class FormCookies(dough: Dough, sender: ActorRef[Manager.Command])

  val form: Behaviors.Receive[FormCookies] = Behaviors.receiveMessage {
    case FormCookies(dough, sender) =>
      val numberOfCookies = makeCookies(dough.weight)
      sender ! ReceiveRawCookies(RawCookies(numberOfCookies))
      form
  }

  private val cookieWeight = 60
  private def makeCookies(weight: Int): Int = weight / cookieWeight
} 
Example 44
Source File: Shop.scala    From Learn-Scala-Programming   with MIT License 5 votes vote down vote up
package ch12

import akka.actor.typed.{ActorRef, ActorSystem, Behavior}
import akka.actor.typed.receptionist.{Receptionist, ServiceKey}
import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.receptionist.Receptionist._
import ch12.Bakery.Groceries
import ch12.Manager.ReceiveGroceries
import ch12.Shop.seller
import com.typesafe.config.ConfigFactory

object Store extends App {
  val config = ConfigFactory.load("grocery.conf")
  val system = ActorSystem(seller(Shop.systemReceptionist), "Typed-Bakery", config)
}
object Shop {
  final case class ShoppingList(eggs: Int,
                                flour: Int,
                                sugar: Int,
                                chocolate: Int)
  final case class SellByList(list: ShoppingList,
                              toWhom: ActorRef[Manager.Command])

  val SellerKey = ServiceKey[SellByList]("GrocerySeller")

  type ReceptionistFactory = ActorContext[SellByList] => ActorRef[Receptionist.Command]

  val systemReceptionist: ReceptionistFactory = _.system.receptionist

  def seller(receptionist: ReceptionistFactory): Behavior[SellByList] = Behaviors.setup { ctx ⇒
    receptionist(ctx) ! Register(SellerKey, ctx.self)
    Behaviors.receiveMessage[SellByList] {
      case SellByList(list, toWhom) ⇒
        import list._
        toWhom ! ReceiveGroceries(Groceries(eggs, flour, sugar, chocolate))
        Behaviors.same
    }
  }

} 
Example 45
Source File: DistributedDataTracker.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.akka_oled

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import akka.cluster.ddata.typed.scaladsl.{DistributedData, Replicator}
import akka.cluster.ddata.{LWWMap, LWWMapKey, SelfUniqueAddress}
import akkapi.cluster.OledDriver
import akkapi.cluster.OledDriver.UpdateView

object DistributedDataTracker {

  sealed trait Command

  case class UpdateStatus(name: String, status: String) extends Command

  case class Get(name: String, replyTo: ActorRef[String]) extends Command

  case class SubscribeResponse(rsp: Replicator.SubscribeResponse[LWWMap[String, String]]) extends Command

  case class InternalUpdateResponse(rsp: Replicator.UpdateResponse[LWWMap[String, String]]) extends Command

  private val NO_DATA = "No data"

  def apply(screenIndex: Int,
            key: LWWMapKey[String, String],
            oledDriver: ActorRef[OledDriver.Command]): Behavior[DistributedDataTracker.Command] =
    Behaviors.setup { context =>

      oledDriver ! UpdateView(screenIndex, NO_DATA)

      implicit val node: SelfUniqueAddress = DistributedData(context.system).selfUniqueAddress
      DistributedData.withReplicatorMessageAdapter[Command, LWWMap[String, String]] {
        replicatorAdapter =>
          replicatorAdapter.subscribe(key, SubscribeResponse.apply)

          def updated(cachedValue: Map[String, String]): Behavior[Command] = {
            Behaviors.receiveMessage[Command] {
              case UpdateStatus(name, status) =>
                replicatorAdapter.askUpdate(
                  askReplyTo => Replicator.Update(key, LWWMap.empty[String, String],
                    Replicator.WriteLocal, askReplyTo)(_ :+ (name -> status)),
                  InternalUpdateResponse.apply)
                val updatedValue = cachedValue + (name -> status)
                oledDriver ! UpdateView(screenIndex, renderState(updatedValue))
                updated(updatedValue)

              case Get(name, replyTo) =>
                replyTo ! cachedValue.getOrElse(name, "")
                Behaviors.same

              case InternalUpdateResponse(_) =>
                Behaviors.same

              case SubscribeResponse([email protected](`key`)) =>
                val value = chg.get(key).entries
                oledDriver ! UpdateView(screenIndex, renderState(value))
                updated(value)
            }

          }

          updated(Map.empty[String, String])
      }

    }

  private def renderState(cachedValue: Map[String, String]): String = {
    if (cachedValue.nonEmpty)
      cachedValue.map[String] { case (key, value) => key + ": " + value + "        " }.mkString("\n")
    else
      NO_DATA
  }
} 
Example 46
Source File: Routes.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.akka_oled

import akka.actor.typed.scaladsl.AskPattern._
import akka.actor.typed.{ActorRef, ActorSystem}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.server.Directives.{as, complete, concat, entity, get, onSuccess, pathPrefix, post, _}
import akka.http.scaladsl.server.Route
import akka.util.Timeout
import com.lightbend.akka_oled.DistributedDataTracker.{Get, UpdateStatus}
import com.lightbend.akka_oled.Main.NodeStatus

import scala.concurrent.duration._

class Routes(tracker: ActorRef[DistributedDataTracker.Command])(implicit system: ActorSystem[_]) extends SprayJsonSupport {
  implicit val timeout: Timeout = 8.seconds

  val route: Route =
    pathPrefix("status" / "[0-9a-zA-Z]+".r) {
      node =>
        concat(
          get {
            onSuccess(tracker.ask[String](Get(node, _))) {
              value => complete(value + "\n")
            }
          },
          post {
            entity(as[NodeStatus]) { status =>
              tracker ! UpdateStatus(node, status.status)
              complete("Ok\n")
            }
          }
        )
    }

} 
Example 47
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 48
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 49
Source File: WsAddressState.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.api.ws.state

import akka.actor.typed.ActorRef
import cats.syntax.option._
import com.wavesplatform.dex.api.ws.entities.{WsBalances, WsOrder}
import com.wavesplatform.dex.api.ws.protocol.WsAddressChanges
import com.wavesplatform.dex.domain.account.Address
import com.wavesplatform.dex.domain.asset.Asset
import com.wavesplatform.dex.domain.model.Denormalization._
import com.wavesplatform.dex.domain.order.Order
import com.wavesplatform.dex.error.ErrorFormatterContext
import com.wavesplatform.dex.model.{AcceptedOrder, OrderStatus}

case class WsAddressState(address: Address,
                          activeSubscription: Map[ActorRef[WsAddressChanges], Long],
                          pendingSubscription: Set[ActorRef[WsAddressChanges]],
                          changedSpendableAssets: Set[Asset],
                          changedReservableAssets: Set[Asset],
                          ordersChanges: Map[Order.Id, WsOrder]) { // TODO Probably use an ordered Map and pass it to WsAddressChanges

  val hasActiveSubscriptions: Boolean = activeSubscription.nonEmpty
  val hasChanges: Boolean             = getAllChangedAssets.nonEmpty || ordersChanges.nonEmpty

  def getAllChangedAssets: Set[Asset]  = changedSpendableAssets ++ changedReservableAssets
  def getAllOrderChanges: Seq[WsOrder] = ordersChanges.values.toSeq

  def addPendingSubscription(subscriber: ActorRef[WsAddressChanges]): WsAddressState =
    copy(pendingSubscription = pendingSubscription + subscriber)

  def flushPendingSubscriptions(): WsAddressState =
    copy(activeSubscription = activeSubscription ++ pendingSubscription.iterator.map(_ -> 0L), pendingSubscription = Set.empty)

  def removeSubscription(subscriber: ActorRef[WsAddressChanges]): WsAddressState = {
    if (activeSubscription.size == 1) copy(activeSubscription = Map.empty).cleanChanges()
    else copy(activeSubscription = activeSubscription - subscriber)
  }

  def putReservedAssets(diff: Set[Asset]): WsAddressState  = copy(changedReservableAssets = changedReservableAssets ++ diff)
  def putSpendableAssets(diff: Set[Asset]): WsAddressState = copy(changedSpendableAssets = changedSpendableAssets ++ diff)

  def putOrderUpdate(id: Order.Id, update: WsOrder): WsAddressState = copy(ordersChanges = ordersChanges + (id -> update))

  def putOrderStatusUpdate(id: Order.Id, newStatus: OrderStatus): WsAddressState =
    putOrderUpdate(
      id = id,
      update = ordersChanges.getOrElse(id, WsOrder(id)).copy(status = newStatus.name.some)
    )

  def putOrderFillingInfoAndStatusUpdate(ao: AcceptedOrder, newStatus: OrderStatus)(implicit efc: ErrorFormatterContext): WsAddressState = {

    val ad = efc.assetDecimals(ao.order.assetPair.amountAsset)
    val pd = efc.assetDecimals(ao.order.assetPair.priceAsset)
    val fd = efc.assetDecimals(ao.feeAsset)

    putOrderUpdate(
      id = ao.id,
      update = ordersChanges
        .getOrElse(ao.id, WsOrder(ao.id))
        .copy(
          status = newStatus.name.some,
          filledAmount = ao.fillingInfo.filledAmount.some.map(denormalizeAmountAndFee(_, ad).toDouble),
          filledFee = ao.fillingInfo.filledFee.some.map(denormalizeAmountAndFee(_, fd).toDouble),
          avgWeighedPrice = ao.fillingInfo.avgWeighedPrice.some.map(denormalizePrice(_, ad, pd).toDouble)
        )
    )
  }

  def sendSnapshot(balances: Map[Asset, WsBalances], orders: Seq[WsOrder]): Unit = {
    val snapshot = WsAddressChanges(address, balances, orders, 0)
    pendingSubscription.foreach(_ ! snapshot)
  }

  def sendDiffs(balances: Map[Asset, WsBalances], orders: Seq[WsOrder]): WsAddressState = copy(
    activeSubscription = activeSubscription.map { // dirty but one pass
      case (conn, updateId) =>
        val newUpdateId = WsAddressState.getNextUpdateId(updateId)
        conn ! WsAddressChanges(address, balances, orders, newUpdateId)
        conn -> newUpdateId
    }
  )

  def cleanChanges(): WsAddressState = copy(changedSpendableAssets = Set.empty, changedReservableAssets = Set.empty, ordersChanges = Map.empty)
}

object WsAddressState {

  def empty(address: Address): WsAddressState = WsAddressState(address, Map.empty, Set.empty, Set.empty, Set.empty, Map.empty)
  val numberMaxSafeInteger                    = 9007199254740991L

  def getNextUpdateId(currentUpdateId: Long): Long = if (currentUpdateId == numberMaxSafeInteger) 1 else currentUpdateId + 1
} 
Example 50
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 51
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 52
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 53
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 54
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 55
Source File: ButtonPushHandlers.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akka_oled

import akka.actor.typed.ActorRef
import akkapi.cluster.OledDriver
import com.pi4j.io.gpio.{GpioController, GpioFactory, GpioPinDigitalInput, PinPullResistance, RaspiPin}
import com.pi4j.io.gpio.event.{GpioPinDigitalStateChangeEvent, GpioPinListenerDigital}



trait ButtonPushHandlers {
   val gpio: GpioController = GpioFactory.getInstance
   val DELAY = 300
   var counter = 0
   val lastClick = 0
   val RESET_DELAY = 1000
   private[this] def diff(last: Option[Long]): Long = System.currentTimeMillis() - last.getOrElse(0L)

   def onStop(): Unit = gpio.removeAllListeners()

   def initButtonPush(actor: ActorRef[OledDriver.Command]): Unit = {
      val upButton: GpioPinDigitalInput = gpio.provisionDigitalInputPin(RaspiPin.GPIO_16, PinPullResistance.PULL_UP)

      upButton.addListener(new GpioPinListenerDigital() {
         var lastPush: Option[Long] = None

         override def handleGpioPinDigitalStateChangeEvent(event: GpioPinDigitalStateChangeEvent): Unit = {
            counter += 1
            if (event.getState.isLow && diff(lastPush) > DELAY) { // display pin state on console
               if(diff(lastPush) < RESET_DELAY){
                  actor ! OledDriver.FirstScreen
               } else {
                  actor ! OledDriver.NextScreen
               }
               lastPush = Some(System.currentTimeMillis())
            }
         }
      })
   }
} 
Example 56
Source File: LedPulser.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster

import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler}
import akka.actor.typed.{ActorRef, Behavior}
import org.neopixel.Neopixel

import scala.concurrent.duration.FiniteDuration

object LedPulser {
  sealed trait Command
  final case class PulseLed(ledNumber: Int,
                            color: Long,
                            flashDuration: FiniteDuration,
                            overRunColor: Option[Long]) extends Command
  private final case class StopPulse(ledNumber: Int) extends Command

  def apply(settings: Settings, ledStripDriver: ActorRef[LedStripDriver.Command]): Behavior[Command] = Behaviors.setup { context =>
    Behaviors.withTimers { timers =>
      new LedPulser(settings, context, timers, ledStripDriver).run(Neopixel.Black)
    }
  }
}

class LedPulser(settings: Settings,
                context: ActorContext[LedPulser.Command],
                timers: TimerScheduler[LedPulser.Command],
                ledStripDriver: ActorRef[LedStripDriver.Command]) {
  import LedPulser._

  def run(currentColor: Long): Behavior[Command] = Behaviors.receiveMessagePartial {
    case PulseLed(ledNumber, color, flashDuration, overRunColor) if color != currentColor =>
      timers.startTimerWithFixedDelay(StopPulse(ledNumber), flashDuration)
      ledStripDriver ! LedStripDriver.SetLedState(ledNumber, color, None)
      run(color)
    case PulseLed(ledNumber, color, flashDuration, overRunColor) =>
      // If the new color is the same as the current color, it implies that
      // the timer is still running. Obviously, no need to update the color
      // on the LED. Running `startTimerWithFixedDelay` will cancel the current
      // timer and start a "fresh" one
      timers.startTimerWithFixedDelay(StopPulse(ledNumber), flashDuration)
      run(color)
    case StopPulse(ledNumber) =>
      ledStripDriver ! LedStripDriver.SetLedState(ledNumber, Neopixel.Black, None)
      run(Neopixel.Black)
  }
} 
Example 57
Source File: OledClusterVisualizer.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import akkapi.cluster.ClusterStatusTracker.{IsLeader, IsNoLeader, NodeDown, NodeExiting, NodeJoining, NodeLeaving, NodeRemoved, NodeState, NodeUnreachable, NodeUp, NodeWeaklyUp, PiClusterSingletonNotRunning, PiClusterSingletonRunning}

object OledClusterVisualizer {

  def apply(screenNumber: Int,
            settings: Settings,
            oledDriver: ActorRef[OledDriver.Command]): Behavior[NodeState] =
    Behaviors.setup { context =>
      new OledClusterVisualizer(screenNumber, settings, oledDriver).running(
        nodes = Map.empty[Int, String],
        leader = None
      )
    }
}

class OledClusterVisualizer private(screenNumber: Int,
                                    settings: Settings,
                                    oledDriver: ActorRef[OledDriver.Command]) {
  private val thisHost = settings.config.getString("akka.remote.artery.canonical.hostname")

  private def updateState(nodeId: Int, status: String)(implicit nodes: Map[Int, String]): Map[Int, String] = {
    nodes + (nodeId -> status)
  }

  def running(implicit nodes: Map[Int, String],
              leader: Option[Int]
             ): Behavior[NodeState] = Behaviors
    .receiveMessage[NodeState] {
      case NodeUp(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Up"))
      case NodeJoining(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Joining"))
      case NodeLeaving(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Left"))
      case NodeExiting(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Exited"))
      case NodeRemoved(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Removed"))
      case NodeDown(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Down"))
      case NodeUnreachable(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Unreachable"))
      case NodeWeaklyUp(nodeLedId) =>
        setClusterViewState(updateState(nodeLedId, "Weakly Up"))
      case IsLeader =>
        setLeader(Some(settings.HostToLedMapping(thisHost)))
      case IsNoLeader(address) =>
        setLeader(address)
      case PiClusterSingletonRunning =>
        Behaviors.same
      case PiClusterSingletonNotRunning =>
        Behaviors.same
    }

  private def render(nodes: Map[Int, String], leader: Option[Int]): String = {
    val stringBuilder = new StringBuilder
    //TODO
    (0 to 2).foreach(i => stringBuilder ++= "Node " + i + ": " + nodes.getOrElse(i, "N/A") + "\n")
    stringBuilder ++= "Leader: " + leader.getOrElse("N/A")
    stringBuilder.toString()
  }

  private def setClusterViewState(nodes: Map[Int, String])
                                 (implicit leader: Option[Int]): Behavior[NodeState] = {
    oledDriver ! OledDriver.UpdateView(screenNumber, render(nodes, leader))
    running(nodes, leader)
  }

  private def setLeader(leader: Option[Int])
                       (implicit nodes: Map[Int, String]): Behavior[NodeState] = {
    oledDriver ! OledDriver.UpdateView(screenNumber, render(nodes, leader))
    running(nodes, leader)
  }
} 
Example 58
Source File: PiClusterSingleton.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster



import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop}
import akkapi.cluster.{ClusterStatusTracker, Settings}

object PiClusterSingleton {

  sealed trait Command
  final case object Ping extends Command

  def apply(settings: Settings, clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]): Behavior[Command] = {
    Behaviors.setup { context =>
      new PiClusterSingleton(context, settings, clusterStatusTracker).run()
    }
  }
}

class PiClusterSingleton private (context: ActorContext[PiClusterSingleton.Command],
                         settings: Settings,
                         clusterStatusTracker: ActorRef[ClusterStatusTracker.ClusterEvent]) {

  import PiClusterSingleton._

  // Cluster singleton has been started on this node
  clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonOnNode

  def run(): Behavior[Command] = Behaviors.receiveMessage[Command] {
    case Ping =>
      context.log.info(s"PiClusterSingleton was pinged")
      Behaviors.same
  }.receiveSignal {
    case (_, signal) if signal == PostStop =>
      clusterStatusTracker ! ClusterStatusTracker.PiClusterSingletonNotOnNode
      Behaviors.same
  }

} 
Example 59
Source File: SudokuProgressTracker.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster.sudoku

import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior}

object SudokuProgressTracker {

  sealed trait Command
  final case class NewUpdatesInFlight(count: Int) extends Command
  final case class SudokuDetailState(index: Int, state: ReductionSet) extends Command
  // My responses
  sealed trait Response
  final case class Result(sudoku: Sudoku) extends Response

  def apply(rowDetailProcessors: Map[Int, ActorRef[SudokuDetailProcessor.Command]],
            sudokuSolver: ActorRef[Response]): Behavior[Command] =
    Behaviors.setup { context =>
      new SudokuProgressTracker(rowDetailProcessors, context, sudokuSolver).trackProgress(updatesInFlight = 0)
    }
}

class SudokuProgressTracker private (rowDetailProcessors: Map[Int, ActorRef[SudokuDetailProcessor.Command]],
                            context: ActorContext[SudokuProgressTracker.Command],
                            sudokuSolver: ActorRef[SudokuProgressTracker.Response]) {

  import SudokuProgressTracker._

  def trackProgress(updatesInFlight: Int): Behavior[Command] = Behaviors.receiveMessagePartial {
    case NewUpdatesInFlight(updateCount) if updatesInFlight - 1 == 0 =>
      rowDetailProcessors.foreach { case (_, processor) => processor ! SudokuDetailProcessor.GetSudokuDetailState(context.self) }
      collectEndState()
    case NewUpdatesInFlight(updateCount) =>
      trackProgress(updatesInFlight + updateCount)
  }

  def collectEndState(remainingRows: Int = 9, endState: Vector[SudokuDetailState] = Vector.empty[SudokuDetailState]): Behavior[Command] =
    Behaviors.receiveMessagePartial {
      case detail @ SudokuDetailState(index, state) if remainingRows == 1 =>
        sudokuSolver ! Result((detail +: endState).sortBy { case SudokuDetailState(idx, _) => idx }.map { case SudokuDetailState(_, state) => state})
        trackProgress(updatesInFlight = 0)
      case detail @ SudokuDetailState(index, state) =>
        collectEndState(remainingRows = remainingRows - 1, detail +: endState)
    }
} 
Example 60
Source File: SudokuProblemSender.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package akkapi.cluster.sudoku

import java.io.File

import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler}
import akka.actor.typed.{ActorRef, Behavior}

object SudokuProblemSender {

  sealed trait Command
  case object SendNewSudoku extends Command
  // Wrapped responses
  private final case class SolutionWrapper(result: SudokuSolver.Response) extends Command

  private val rowUpdates: Seq[SudokuDetailProcessor.RowUpdate] =
    SudokuIO.readSudokuFromFile(new File("sudokus/001.sudoku"))
      .map { case (rowIndex, update) => SudokuDetailProcessor.RowUpdate(rowIndex, update) }

  def apply(sudokuSolver: ActorRef[SudokuSolver.Command],
            sudokuSolverSettings: SudokuSolverSettings): Behavior[Command] =
    Behaviors.setup { context =>
      Behaviors.withTimers { timers =>
        new SudokuProblemSender(sudokuSolver, context, timers, sudokuSolverSettings).sending()
      }
    }
}

class SudokuProblemSender private (sudokuSolver: ActorRef[SudokuSolver.Command],
                                   context: ActorContext[SudokuProblemSender.Command],
                                   timers: TimerScheduler[SudokuProblemSender.Command],
                                   sudokuSolverSettings: SudokuSolverSettings) {
  import SudokuProblemSender._

  private val solutionWrapper: ActorRef[SudokuSolver.Response] =
    context.messageAdapter(response => SolutionWrapper(response))

  private val initialSudokuField = rowUpdates.toSudokuField

  private val rowUpdatesSeq = LazyList.continually(
    Seq(
      initialSudokuField,
      initialSudokuField.flipVertically,
      initialSudokuField.flipHorizontally,
      initialSudokuField.flipHorizontally.flipVertically,
      initialSudokuField.flipVertically.flipHorizontally,
      initialSudokuField.columnSwap(0,1),
      initialSudokuField.rowSwap(4,5).rowSwap(0, 2),
      initialSudokuField.randomSwapAround,
      initialSudokuField.randomSwapAround,
      initialSudokuField.rotateCW,
      initialSudokuField.rotateCCW,
      initialSudokuField.rotateCW.rotateCW,
      initialSudokuField.transpose,
      initialSudokuField.randomSwapAround,
      initialSudokuField.rotateCW.transpose,
      initialSudokuField.randomSwapAround,
      initialSudokuField.rotateCCW.transpose,
      initialSudokuField.randomSwapAround,
      initialSudokuField.randomSwapAround,
      initialSudokuField.flipVertically.transpose,
      initialSudokuField.flipVertically.rotateCW,
      initialSudokuField.columnSwap(4,5).columnSwap(0, 2).rowSwap(3,4),
      initialSudokuField.rotateCW.rotateCW.transpose
    ).map(_.toRowUpdates)).flatten.iterator

  private val problemSendInterval = sudokuSolverSettings.ProblemSender.SendInterval
  timers.startTimerAtFixedRate(SendNewSudoku, problemSendInterval) // on a 5 node RPi 4 based cluster in steady state, this can be lowered to about 6ms

  def sending(): Behavior[Command] = Behaviors.receiveMessagePartial {
    case SendNewSudoku =>
      context.log.debug("sending new sudoku problem")
      sudokuSolver ! SudokuSolver.InitialRowUpdates(rowUpdatesSeq.next, solutionWrapper)
      Behaviors.same
    case SolutionWrapper(solution: SudokuSolver.SudokuSolution) =>
      context.log.info(s"${SudokuIO.sudokuPrinter(solution)}")
      Behaviors.same
  }
} 
Example 61
Source File: OledShardingVisualizer.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.akka_oled

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import akka.cluster.sharding.ShardRegion.ShardState
import akkapi.cluster.OledDriver
import akkapi.cluster.OledDriver.UpdateView
import com.lightbend.akka_oled.OledShardingVisualizer.{Notification, ShardRegionState}

object OledShardingVisualizer {

  sealed trait Command

  case class ShardRegionState(shards: Set[ShardState]) extends Command

  case class Notification(name: String, total: Int) extends Command

  def apply(screenIndex: Int,
            oledDriver: ActorRef[OledDriver.Command]): Behavior[OledShardingVisualizer.Command] =
    Behaviors.setup { context =>
      Behaviors.withTimers[Command] { timer =>
        new OledShardingVisualizer(screenIndex, oledDriver).running(
          clients = Map.empty[String, Int],
          shardToClientName = Map.empty[String, Set[String]]
        )
      }
    }
}

class OledShardingVisualizer private(screenIndex: Int,
                                     oledDriver: ActorRef[OledDriver.Command]) {

  def running(clients: Map[String, Int],
              shardToClientName: Map[String, Set[String]]
             ): Behavior[OledShardingVisualizer.Command] = Behaviors
    .receiveMessage[OledShardingVisualizer.Command] {
      case Notification(name, total) =>
        val newClients = clients + (name -> total)
        oledDriver ! UpdateView(screenIndex, renderState(newClients, shardToClientName))
        running(newClients, shardToClientName)
      case ShardRegionState(shards: Set[ShardState]) =>
        val entityIds: Set[String] = shards.flatMap(_.entityIds)

        val newShardToClientName = shards.foldLeft(Map.empty[String, Set[String]]) {
          case (map, value) =>
            map + (value.shardId.toString -> value.entityIds.map(_.toString))
        }

        val withNewClients: Map[String, Int] =
          entityIds.foldLeft(clients)((map, a) => if (clients.get(a).isEmpty) map + (a -> 0) else map)
        //remove old shards
        val updatedClients = withNewClients.filter { case (k, _) => entityIds.contains(k) }

        oledDriver ! UpdateView(screenIndex, renderState(updatedClients, newShardToClientName))
        running(updatedClients, newShardToClientName)
    }

  private def renderState(clients: Map[String, Int],
                          shardToClientName: Map[String, Set[String]]): String = {
    if (clients.nonEmpty)
      shardToClientName.flatMap[String] {
        case (key, names) => names.map {
          name => "Shard#" + key + "->" + name + ": " + clients.getOrElse(name, 0)
        }
      }.mkString("\n")
    else
      "No data"
  }

} 
Example 62
Source File: ClientEntity.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.akka_oled

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import akka.cluster.sharding.typed.scaladsl.EntityTypeKey
import akka.persistence.typed.PersistenceId
import akka.persistence.typed.scaladsl.{Effect, EventSourcedBehavior}
import com.lightbend.akka_oled.OledShardingVisualizer.Notification

object ClientEntity {

  sealed trait Command

  case class PostPoints(name: String, amount: Int)(val replyTo: ActorRef[String]) extends Command

  case class Get(name: String)(val replyTo: ActorRef[Int]) extends Command

  final case class PointsAdded(name: String, points: Int)

  val TypeKey: EntityTypeKey[Command] =
    EntityTypeKey[Command]("ClientEntity")

  final case class ClientPoints(name: String, points: Int, visualizer: ActorRef[Notification]) {
    def add(delta: Int) = copy(points = points + delta)
  }

  private val commandHandler: (ClientPoints, Command) => Effect[PointsAdded, ClientPoints] = {
    (state, cmd) =>
      cmd match {
        case pp@PostPoints(name, amount) =>
          Effect.persist(PointsAdded(name, amount)).thenRun(s => {
            state.visualizer ! Notification(s.name, s.points)
            pp.replyTo ! "Ok\n"
          })
        case g@Get(_) =>
          g.replyTo ! state.points
          state.visualizer ! Notification(state.name, state.points)
          Effect.none
      }
  }

  private val eventHandler: (ClientPoints, PointsAdded) => ClientPoints = {
    (state, evt) => state.add(evt.points)
  }


  def apply(entityId: String, persistenceId: PersistenceId, visualizer: ActorRef[Notification]): Behavior[ClientEntity.Command] =
    Behaviors.setup { _ =>
      EventSourcedBehavior(persistenceId, ClientPoints(entityId, 0, visualizer), commandHandler, eventHandler)
    }
} 
Example 63
Source File: ShardStateTracker.scala    From Pi-Akka-Cluster   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.akka_oled

import akka.actor.typed.{ActorRef, Behavior}
import akka.actor.typed.scaladsl.Behaviors
import akka.cluster.sharding.ShardRegion.CurrentShardRegionState
import akka.cluster.sharding.typed.{ClusterShardingQuery, GetShardRegionState}
import akka.util.Timeout
import com.lightbend.akka_oled.OledShardingVisualizer.ShardRegionState
import scala.concurrent.duration._

object ShardStateTracker {

  implicit val timeout: Timeout = 6.seconds

  def apply(visualizer: ActorRef[OledShardingVisualizer.Command]): Behavior[CurrentShardRegionState] = Behaviors.setup { context =>
    Behaviors.receiveMessage {
      message: CurrentShardRegionState =>
        visualizer.tell(ShardRegionState(message.shards))
        Behaviors.same
    }
  }
}

object ShardStateScheduler {

  implicit val timeout: Timeout = 6.seconds

  case class Tick()

  def apply(shardState: ActorRef[ClusterShardingQuery],
            shardTracker: ActorRef[CurrentShardRegionState]): Behavior[Tick] =
    Behaviors.withTimers { timer =>
      timer.startTimerAtFixedRate(Tick(), 1.second)
      Behaviors.receiveMessage { _: Tick =>
        shardState ! GetShardRegionState(ClientEntity.TypeKey, shardTracker)
        Behaviors.same
      }

    }
}