2014-12-19 15:22:45 +01:00
|
|
|
/**
|
2016-02-23 12:58:39 +01:00
|
|
|
* Copyright (C) 2014-2016 Lightbend Inc. <http://www.lightbend.com>
|
2014-12-19 15:22:45 +01:00
|
|
|
*/
|
|
|
|
|
package docs.stream
|
|
|
|
|
|
|
|
|
|
import scala.annotation.tailrec
|
|
|
|
|
import akka.actor.Props
|
2015-06-23 18:28:53 +02:00
|
|
|
import akka.stream.ActorMaterializer
|
2014-12-19 15:22:45 +01:00
|
|
|
import akka.stream.actor.ActorPublisher
|
2015-01-28 14:19:50 +01:00
|
|
|
import akka.stream.scaladsl.{ Flow, Sink, Source }
|
2016-02-25 14:27:45 +01:00
|
|
|
import akka.testkit.AkkaSpec
|
2014-12-19 15:22:45 +01:00
|
|
|
|
|
|
|
|
object ActorPublisherDocSpec {
|
|
|
|
|
|
|
|
|
|
//#job-manager
|
|
|
|
|
object JobManager {
|
|
|
|
|
def props: Props = Props[JobManager]
|
|
|
|
|
|
|
|
|
|
final case class Job(payload: String)
|
|
|
|
|
case object JobAccepted
|
|
|
|
|
case object JobDenied
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class JobManager extends ActorPublisher[JobManager.Job] {
|
|
|
|
|
import akka.stream.actor.ActorPublisherMessage._
|
|
|
|
|
import JobManager._
|
|
|
|
|
|
|
|
|
|
val MaxBufferSize = 100
|
|
|
|
|
var buf = Vector.empty[Job]
|
|
|
|
|
|
|
|
|
|
def receive = {
|
|
|
|
|
case job: Job if buf.size == MaxBufferSize =>
|
|
|
|
|
sender() ! JobDenied
|
|
|
|
|
case job: Job =>
|
|
|
|
|
sender() ! JobAccepted
|
|
|
|
|
if (buf.isEmpty && totalDemand > 0)
|
|
|
|
|
onNext(job)
|
|
|
|
|
else {
|
|
|
|
|
buf :+= job
|
|
|
|
|
deliverBuf()
|
|
|
|
|
}
|
|
|
|
|
case Request(_) =>
|
|
|
|
|
deliverBuf()
|
|
|
|
|
case Cancel =>
|
|
|
|
|
context.stop(self)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@tailrec final def deliverBuf(): Unit =
|
|
|
|
|
if (totalDemand > 0) {
|
2014-12-20 16:56:22 +01:00
|
|
|
/*
|
|
|
|
|
* totalDemand is a Long and could be larger than
|
|
|
|
|
* what buf.splitAt can accept
|
|
|
|
|
*/
|
2014-12-19 15:22:45 +01:00
|
|
|
if (totalDemand <= Int.MaxValue) {
|
|
|
|
|
val (use, keep) = buf.splitAt(totalDemand.toInt)
|
|
|
|
|
buf = keep
|
|
|
|
|
use foreach onNext
|
|
|
|
|
} else {
|
|
|
|
|
val (use, keep) = buf.splitAt(Int.MaxValue)
|
|
|
|
|
buf = keep
|
|
|
|
|
use foreach onNext
|
|
|
|
|
deliverBuf()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#job-manager
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ActorPublisherDocSpec extends AkkaSpec {
|
|
|
|
|
import ActorPublisherDocSpec._
|
|
|
|
|
|
2015-12-11 14:45:24 +01:00
|
|
|
implicit val materializer = ActorMaterializer()
|
2014-12-19 15:22:45 +01:00
|
|
|
|
|
|
|
|
"illustrate usage of ActorPublisher" in {
|
|
|
|
|
def println(s: String): Unit =
|
|
|
|
|
testActor ! s
|
|
|
|
|
|
|
|
|
|
//#actor-publisher-usage
|
2015-03-31 15:13:57 +02:00
|
|
|
val jobManagerSource = Source.actorPublisher[JobManager.Job](JobManager.props)
|
2015-01-28 14:19:50 +01:00
|
|
|
val ref = Flow[JobManager.Job]
|
2014-12-19 15:22:45 +01:00
|
|
|
.map(_.payload.toUpperCase)
|
|
|
|
|
.map { elem => println(elem); elem }
|
|
|
|
|
.to(Sink.ignore)
|
2015-01-28 14:19:50 +01:00
|
|
|
.runWith(jobManagerSource)
|
2014-12-19 15:22:45 +01:00
|
|
|
|
|
|
|
|
ref ! JobManager.Job("a")
|
|
|
|
|
ref ! JobManager.Job("b")
|
|
|
|
|
ref ! JobManager.Job("c")
|
|
|
|
|
//#actor-publisher-usage
|
|
|
|
|
|
|
|
|
|
expectMsg("A")
|
|
|
|
|
expectMsg("B")
|
|
|
|
|
expectMsg("C")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|