move code to src/test
* so that it compiles and tests pass * fix some additional snip references in getting started
This commit is contained in:
parent
413df8e0f4
commit
59f53e1a22
289 changed files with 45 additions and 45 deletions
27
akka-docs/src/test/scala/docs/cluster/ClusterDocSpec.scala
Normal file
27
akka-docs/src/test/scala/docs/cluster/ClusterDocSpec.scala
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (C) 2015-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package scala.docs.cluster
|
||||
|
||||
import akka.cluster.Cluster
|
||||
import akka.testkit.AkkaSpec
|
||||
|
||||
object ClusterDocSpec {
|
||||
|
||||
val config =
|
||||
"""
|
||||
akka.actor.provider = "cluster"
|
||||
akka.remote.netty.tcp.port = 0
|
||||
"""
|
||||
}
|
||||
|
||||
class ClusterDocSpec extends AkkaSpec(ClusterDocSpec.config) {
|
||||
|
||||
"demonstrate leave" in {
|
||||
//#leave
|
||||
val cluster = Cluster(system)
|
||||
cluster.leave(cluster.selfAddress)
|
||||
//#leave
|
||||
}
|
||||
|
||||
}
|
||||
46
akka-docs/src/test/scala/docs/cluster/FactorialBackend.scala
Normal file
46
akka-docs/src/test/scala/docs/cluster/FactorialBackend.scala
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.Future
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import akka.actor.Actor
|
||||
import akka.actor.ActorLogging
|
||||
import akka.actor.ActorSystem
|
||||
import akka.actor.Props
|
||||
import akka.pattern.pipe
|
||||
|
||||
//#backend
|
||||
class FactorialBackend extends Actor with ActorLogging {
|
||||
|
||||
import context.dispatcher
|
||||
|
||||
def receive = {
|
||||
case (n: Int) =>
|
||||
Future(factorial(n)) map { result => (n, result) } pipeTo sender()
|
||||
}
|
||||
|
||||
def factorial(n: Int): BigInt = {
|
||||
@tailrec def factorialAcc(acc: BigInt, n: Int): BigInt = {
|
||||
if (n <= 1) acc
|
||||
else factorialAcc(acc * n, n - 1)
|
||||
}
|
||||
factorialAcc(BigInt(1), n)
|
||||
}
|
||||
|
||||
}
|
||||
//#backend
|
||||
|
||||
object FactorialBackend {
|
||||
def main(args: Array[String]): Unit = {
|
||||
// Override the configuration of the port when specified as program argument
|
||||
val port = if (args.isEmpty) "0" else args(0)
|
||||
val config = ConfigFactory.parseString(s"akka.remote.netty.tcp.port=$port").
|
||||
withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")).
|
||||
withFallback(ConfigFactory.load("factorial"))
|
||||
|
||||
val system = ActorSystem("ClusterSystem", config)
|
||||
system.actorOf(Props[FactorialBackend], name = "factorialBackend")
|
||||
|
||||
system.actorOf(Props[MetricsListener], name = "metricsListener")
|
||||
}
|
||||
}
|
||||
101
akka-docs/src/test/scala/docs/cluster/FactorialFrontend.scala
Normal file
101
akka-docs/src/test/scala/docs/cluster/FactorialFrontend.scala
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import akka.actor.Actor
|
||||
import akka.actor.ActorLogging
|
||||
import akka.actor.ActorSystem
|
||||
import akka.actor.Props
|
||||
import akka.cluster.Cluster
|
||||
import akka.routing.FromConfig
|
||||
import akka.actor.ReceiveTimeout
|
||||
import scala.util.Try
|
||||
import scala.concurrent.Await
|
||||
|
||||
//#frontend
|
||||
class FactorialFrontend(upToN: Int, repeat: Boolean) extends Actor with ActorLogging {
|
||||
|
||||
val backend = context.actorOf(
|
||||
FromConfig.props(),
|
||||
name = "factorialBackendRouter")
|
||||
|
||||
override def preStart(): Unit = {
|
||||
sendJobs()
|
||||
if (repeat) {
|
||||
context.setReceiveTimeout(10.seconds)
|
||||
}
|
||||
}
|
||||
|
||||
def receive = {
|
||||
case (n: Int, factorial: BigInt) =>
|
||||
if (n == upToN) {
|
||||
log.debug("{}! = {}", n, factorial)
|
||||
if (repeat) sendJobs()
|
||||
else context.stop(self)
|
||||
}
|
||||
case ReceiveTimeout =>
|
||||
log.info("Timeout")
|
||||
sendJobs()
|
||||
}
|
||||
|
||||
def sendJobs(): Unit = {
|
||||
log.info("Starting batch of factorials up to [{}]", upToN)
|
||||
1 to upToN foreach { backend ! _ }
|
||||
}
|
||||
}
|
||||
//#frontend
|
||||
|
||||
object FactorialFrontend {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val upToN = 200
|
||||
|
||||
val config = ConfigFactory.parseString("akka.cluster.roles = [frontend]").
|
||||
withFallback(ConfigFactory.load("factorial"))
|
||||
|
||||
val system = ActorSystem("ClusterSystem", config)
|
||||
system.log.info("Factorials will start when 2 backend members in the cluster.")
|
||||
//#registerOnUp
|
||||
Cluster(system) registerOnMemberUp {
|
||||
system.actorOf(
|
||||
Props(classOf[FactorialFrontend], upToN, true),
|
||||
name = "factorialFrontend")
|
||||
}
|
||||
//#registerOnUp
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// not used, only for documentation
|
||||
abstract class FactorialFrontend2 extends Actor {
|
||||
//#router-lookup-in-code
|
||||
import akka.cluster.routing.ClusterRouterGroup
|
||||
import akka.cluster.routing.ClusterRouterGroupSettings
|
||||
import akka.cluster.metrics.AdaptiveLoadBalancingGroup
|
||||
import akka.cluster.metrics.HeapMetricsSelector
|
||||
|
||||
val backend = context.actorOf(
|
||||
ClusterRouterGroup(
|
||||
AdaptiveLoadBalancingGroup(HeapMetricsSelector),
|
||||
ClusterRouterGroupSettings(
|
||||
totalInstances = 100, routeesPaths = List("/user/factorialBackend"),
|
||||
allowLocalRoutees = true, useRole = Some("backend"))).props(),
|
||||
name = "factorialBackendRouter2")
|
||||
//#router-lookup-in-code
|
||||
}
|
||||
|
||||
// not used, only for documentation
|
||||
abstract class FactorialFrontend3 extends Actor {
|
||||
//#router-deploy-in-code
|
||||
import akka.cluster.routing.ClusterRouterPool
|
||||
import akka.cluster.routing.ClusterRouterPoolSettings
|
||||
import akka.cluster.metrics.AdaptiveLoadBalancingPool
|
||||
import akka.cluster.metrics.SystemLoadAverageMetricsSelector
|
||||
|
||||
val backend = context.actorOf(
|
||||
ClusterRouterPool(AdaptiveLoadBalancingPool(
|
||||
SystemLoadAverageMetricsSelector), ClusterRouterPoolSettings(
|
||||
totalInstances = 100, maxInstancesPerNode = 3,
|
||||
allowLocalRoutees = false, useRole = Some("backend"))).props(Props[FactorialBackend]),
|
||||
name = "factorialBackendRouter3")
|
||||
//#router-deploy-in-code
|
||||
}
|
||||
46
akka-docs/src/test/scala/docs/cluster/MetricsListener.scala
Normal file
46
akka-docs/src/test/scala/docs/cluster/MetricsListener.scala
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
//#metrics-listener
|
||||
import akka.actor.ActorLogging
|
||||
import akka.actor.Actor
|
||||
import akka.cluster.Cluster
|
||||
import akka.cluster.metrics.ClusterMetricsEvent
|
||||
import akka.cluster.metrics.ClusterMetricsChanged
|
||||
import akka.cluster.ClusterEvent.CurrentClusterState
|
||||
import akka.cluster.metrics.NodeMetrics
|
||||
import akka.cluster.metrics.StandardMetrics.HeapMemory
|
||||
import akka.cluster.metrics.StandardMetrics.Cpu
|
||||
import akka.cluster.metrics.ClusterMetricsExtension
|
||||
|
||||
class MetricsListener extends Actor with ActorLogging {
|
||||
val selfAddress = Cluster(context.system).selfAddress
|
||||
val extension = ClusterMetricsExtension(context.system)
|
||||
|
||||
// Subscribe unto ClusterMetricsEvent events.
|
||||
override def preStart(): Unit = extension.subscribe(self)
|
||||
|
||||
// Unsubscribe from ClusterMetricsEvent events.
|
||||
override def postStop(): Unit = extension.unsubscribe(self)
|
||||
|
||||
def receive = {
|
||||
case ClusterMetricsChanged(clusterMetrics) =>
|
||||
clusterMetrics.filter(_.address == selfAddress) foreach { nodeMetrics =>
|
||||
logHeap(nodeMetrics)
|
||||
logCpu(nodeMetrics)
|
||||
}
|
||||
case state: CurrentClusterState => // Ignore.
|
||||
}
|
||||
|
||||
def logHeap(nodeMetrics: NodeMetrics): Unit = nodeMetrics match {
|
||||
case HeapMemory(address, timestamp, used, committed, max) =>
|
||||
log.info("Used heap: {} MB", used.doubleValue / 1024 / 1024)
|
||||
case _ => // No heap info.
|
||||
}
|
||||
|
||||
def logCpu(nodeMetrics: NodeMetrics): Unit = nodeMetrics match {
|
||||
case Cpu(address, timestamp, Some(systemLoadAverage), cpuCombined, cpuStolen, processors) =>
|
||||
log.info("Load: {} ({} processors)", systemLoadAverage, processors)
|
||||
case _ => // No cpu info.
|
||||
}
|
||||
}
|
||||
//#metrics-listener
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import akka.cluster.Cluster
|
||||
import akka.cluster.ClusterEvent._
|
||||
import akka.actor.ActorLogging
|
||||
import akka.actor.Actor
|
||||
|
||||
class SimpleClusterListener extends Actor with ActorLogging {
|
||||
|
||||
val cluster = Cluster(context.system)
|
||||
|
||||
// subscribe to cluster changes, re-subscribe when restart
|
||||
override def preStart(): Unit = {
|
||||
//#subscribe
|
||||
cluster.subscribe(self, initialStateMode = InitialStateAsEvents,
|
||||
classOf[MemberEvent], classOf[UnreachableMember])
|
||||
//#subscribe
|
||||
}
|
||||
override def postStop(): Unit = cluster.unsubscribe(self)
|
||||
|
||||
def receive = {
|
||||
case MemberUp(member) =>
|
||||
log.info("Member is Up: {}", member.address)
|
||||
case UnreachableMember(member) =>
|
||||
log.info("Member detected as unreachable: {}", member)
|
||||
case MemberRemoved(member, previousStatus) =>
|
||||
log.info(
|
||||
"Member is Removed: {} after {}",
|
||||
member.address, previousStatus)
|
||||
case _: MemberEvent => // ignore
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import akka.cluster.Cluster
|
||||
import akka.cluster.ClusterEvent._
|
||||
import akka.actor.ActorLogging
|
||||
import akka.actor.Actor
|
||||
|
||||
class SimpleClusterListener2 extends Actor with ActorLogging {
|
||||
|
||||
val cluster = Cluster(context.system)
|
||||
|
||||
// subscribe to cluster changes, re-subscribe when restart
|
||||
override def preStart(): Unit = {
|
||||
//#subscribe
|
||||
cluster.subscribe(self, classOf[MemberEvent], classOf[UnreachableMember])
|
||||
//#subscribe
|
||||
}
|
||||
override def postStop(): Unit = cluster.unsubscribe(self)
|
||||
|
||||
def receive = {
|
||||
case state: CurrentClusterState =>
|
||||
log.info("Current members: {}", state.members.mkString(", "))
|
||||
case MemberUp(member) =>
|
||||
log.info("Member is Up: {}", member.address)
|
||||
case UnreachableMember(member) =>
|
||||
log.info("Member detected as unreachable: {}", member)
|
||||
case MemberRemoved(member, previousStatus) =>
|
||||
log.info(
|
||||
"Member is Removed: {} after {}",
|
||||
member.address, previousStatus)
|
||||
case _: MemberEvent => // ignore
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import language.postfixOps
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.Actor
|
||||
import akka.actor.ActorRef
|
||||
import akka.actor.ActorSystem
|
||||
import akka.actor.Props
|
||||
import akka.actor.RootActorPath
|
||||
import akka.cluster.Cluster
|
||||
import akka.cluster.ClusterEvent.CurrentClusterState
|
||||
import akka.cluster.ClusterEvent.MemberUp
|
||||
import akka.cluster.Member
|
||||
import akka.cluster.MemberStatus
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
//#backend
|
||||
class TransformationBackend extends Actor {
|
||||
|
||||
val cluster = Cluster(context.system)
|
||||
|
||||
// subscribe to cluster changes, MemberUp
|
||||
// re-subscribe when restart
|
||||
override def preStart(): Unit = cluster.subscribe(self, classOf[MemberUp])
|
||||
override def postStop(): Unit = cluster.unsubscribe(self)
|
||||
|
||||
def receive = {
|
||||
case TransformationJob(text) => sender() ! TransformationResult(text.toUpperCase)
|
||||
case state: CurrentClusterState =>
|
||||
state.members.filter(_.status == MemberStatus.Up) foreach register
|
||||
case MemberUp(m) => register(m)
|
||||
}
|
||||
|
||||
def register(member: Member): Unit =
|
||||
if (member.hasRole("frontend"))
|
||||
context.actorSelection(RootActorPath(member.address) / "user" / "frontend") !
|
||||
BackendRegistration
|
||||
}
|
||||
//#backend
|
||||
|
||||
object TransformationBackend {
|
||||
def main(args: Array[String]): Unit = {
|
||||
// Override the configuration of the port when specified as program argument
|
||||
val port = if (args.isEmpty) "0" else args(0)
|
||||
val config = ConfigFactory.parseString(s"akka.remote.netty.tcp.port=$port").
|
||||
withFallback(ConfigFactory.parseString("akka.cluster.roles = [backend]")).
|
||||
withFallback(ConfigFactory.load())
|
||||
|
||||
val system = ActorSystem("ClusterSystem", config)
|
||||
system.actorOf(Props[TransformationBackend], name = "backend")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
import language.postfixOps
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.Actor
|
||||
import akka.actor.ActorRef
|
||||
import akka.actor.ActorSystem
|
||||
import akka.actor.Props
|
||||
import akka.actor.Terminated
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
//#frontend
|
||||
class TransformationFrontend extends Actor {
|
||||
|
||||
var backends = IndexedSeq.empty[ActorRef]
|
||||
var jobCounter = 0
|
||||
|
||||
def receive = {
|
||||
case job: TransformationJob if backends.isEmpty =>
|
||||
sender() ! JobFailed("Service unavailable, try again later", job)
|
||||
|
||||
case job: TransformationJob =>
|
||||
jobCounter += 1
|
||||
backends(jobCounter % backends.size) forward job
|
||||
|
||||
case BackendRegistration if !backends.contains(sender()) =>
|
||||
context watch sender()
|
||||
backends = backends :+ sender()
|
||||
|
||||
case Terminated(a) =>
|
||||
backends = backends.filterNot(_ == a)
|
||||
}
|
||||
}
|
||||
//#frontend
|
||||
|
||||
object TransformationFrontend {
|
||||
def main(args: Array[String]): Unit = {
|
||||
// Override the configuration of the port when specified as program argument
|
||||
val port = if (args.isEmpty) "0" else args(0)
|
||||
val config = ConfigFactory.parseString(s"akka.remote.netty.tcp.port=$port").
|
||||
withFallback(ConfigFactory.parseString("akka.cluster.roles = [frontend]")).
|
||||
withFallback(ConfigFactory.load())
|
||||
|
||||
val system = ActorSystem("ClusterSystem", config)
|
||||
val frontend = system.actorOf(Props[TransformationFrontend], name = "frontend")
|
||||
|
||||
val counter = new AtomicInteger
|
||||
import system.dispatcher
|
||||
system.scheduler.schedule(2.seconds, 2.seconds) {
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
(frontend ? TransformationJob("hello-" + counter.incrementAndGet())) onSuccess {
|
||||
case result => println(result)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package scala.docs.cluster
|
||||
|
||||
//#messages
|
||||
final case class TransformationJob(text: String)
|
||||
final case class TransformationResult(text: String)
|
||||
final case class JobFailed(reason: String, job: TransformationJob)
|
||||
case object BackendRegistration
|
||||
//#messages
|
||||
Loading…
Add table
Add a link
Reference in a new issue