Do i need to create ActorMaterializer multiple times? - scala

I have an app that generate reports, with akka-http + akka-actors + akka-camel + akka-streams. When a post request arrives , the ActiveMqProducerActor enqueue the request into ActiveMq Broker. Then the ActiveMqConsumerActor consumes the message and start the task using akka-streams(in this actor i need the materializer) .
The main class create the ActorSystem and the ActorMaterializer, but i dont know how is the correct way to "inject" the materializer into the akka-actor
object ReportGeneratorApplication extends App {
implicit val system: ActorSystem = ActorSystem()
implicit val executor = system.dispatcher
implicit val materializer = ActorMaterializer()
val camelExtension: Camel = CamelExtension(system);
val amqc: ActiveMQComponent = ActiveMQComponent.activeMQComponent(env.getString("jms.url"))
amqc.setUsePooledConnection(true)
amqc.setAsyncConsumer(true)
amqc.setTrustAllPackages(true)
amqc.setConcurrentConsumers(1)
camelExtension.context.addComponent("jms", amqc);
val jmsProducer: ActorRef = system.actorOf(Props[ActiveMQProducerActor])
//Is this the correct way to pass the materializer?
val jmsConsumer: ActorRef = system.actorOf(Props(new ActiveMQConsumerActor()(materializer)), name = "jmsConsumer")
val endpoint: ReportEndpoint = new ReportEndpoint(jmsProducer);
Http().bindAndHandle(endpoint.routes, "localhost", 8881)
}
The ReportEndPoint class, that have the jmsProducerActor . Mongo is a trait with CRUD methods. JsonSupport(==SprayJsonSupport)
class ReportEndpoint(jmsProducer: ActorRef)
(implicit val system:ActorSystem,
implicit val executor: ExecutionContext,
implicit val materializer : ActorMaterializer)
extends JsonSupport with Mongo {
val routes =
pathPrefix("reports"){
post {
path("generate"){
entity(as[DataRequest]) { request =>
val id = java.util.UUID.randomUUID.toString
// **Enqueue the request into ActiveMq**
jmsProducer ! request
val future: Future[Seq[Completed]] = insertReport(request)
complete {
future.map[ToResponseMarshallable](r => r.head match {
case r : Completed => println(r); s"Reporte Generado con id $id"
case _ => HttpResponse(StatusCodes.InternalServerError, entity = "Error al generar reporte")
})
}
}
}
} ....
The idea of ActiveMqConsumerActor, is send the messages, with streams and backpressure, one by one,because ReportBuilderActor makes many mongo operations (and the datacenter it`s not very good).
//Is this the correct way to pass the materializer??
class ActiveMQConsumerActor (implicit materializer : ActorMaterializer) extends Consumer with Base {
override def endpointUri: String = env.getString("jms.queue")
val log = Logging(context.system, this)
val reportActor: ActorRef = context.actorOf(Props(new ReportBuilderActor()(materializer)), name = "reportActor")
override def receive: Receive = {
case msg: CamelMessage => msg.body match {
case data: DataRequest => {
//I need only one task running
Source.single(data).buffer(1, OverflowStrategy.backpressure).to(Sink.foreach(d => reportActor ! d)).run()
}
case _ => log.info("Invalid")
}
case _ => UnhandledMessage
}
}
Is a good idea have implicit values in companion objects?
Thanks!!

Related

Function never reached in Akka Streams Source mapping

Given the following code:
class MigrationHandler #Inject()(database: Database, doUpdate: UpdateHandler)
(implicit #PropagateContext executor: ExecutionContext, actorSystem: ActorSystem)
extends Handler with Logging {
implicit val materializer: ActorMaterializer = ActorMaterializer()
val buttonTypeId = "someId1"
val promotionButtonTypeId = "someId2"
val typeId3 = "someId3"
val typeId4 = "someId4"
val typeIds = Seq[String](buttonTypeId, promotionButtonTypeId, typeId3, typeId4)
def apply(requestHeaders: Headers): Seq[Future[Done]] = {
for {
typeId <- typeIds
result = database.allByType(typeId)
.map(contents => contents.map(content => migrate(content, typeId))
.map(migratedContent => doUpdate(ContentId(migratedContent.id),
NewContent(migratedContent.raw, isDefaultContent = false), requestHeaders))
.runForeach(_ => ())).flatten
} yield result
}
def migrate(content: SomeContent, typeId: String): SomeContent = {
logger.info(s"$content with type $typeId")
content
}}
Future[Source[SomeContent, _]] is returned by the database.allByType(typeId)
In unit test where I am mocking database.allByType(typeId) to return Source.single(SomeContent()), I saw that I wasn't able reach the migrate function. Any idea what could be the problem here?

Answer ask in AkkaTestKit

I'm trying to test my actor logic with AkkaTestKit. The problem is that my actor uses ask pattern. So I need to answer somehow. It look as this:
case class AskExecution(id: Long)
override def receive: Receive = {
case id : Long =>
implicit val dispatcher = context.dispatcher
implicit val timeout = Timeout(10 seconds)
val executor = sender
//How to answer this?
val f = executor ? AskExecution(id) map(v => v.asInstanceOf[Option[Long]])
f.onComplete{
case Success(k) =>
case Failure(_) =>
}
}
In test I use it as follows:
val ca = TestActorRef(new TheActor())
ca ! 0L //I send 0, Now I want to answer the ask
//How to do so?
To make your code easier to test, give your actor a reference to the executor actor (the actor that handles the AskExecution message).
import akka.pattern.pipe
class TheActor(executor: ActorRef) extends Actor {
def receive = {
case id: Long =>
val s = sender
implicit val dispatcher = context.dispatcher
implicit val timeout = 10.seconds
(executor ? AskExecution(id)).mapTo[Option[Long]].pipeTo(s)
}
class Executor extends Actor {
def receive = {
case AskExecution(id) =>
// do something to get a result
val result: Option[Long] = ???
sender ! result
}
}
To test, assuming your test class extends TestKit and mixes in the ImplicitSender trait:
val executor = system.actorOf(Props[Executor])
val theActor = system.actorOf(Props(classOf[TheActor], executor))
within(10.seconds) {
theActor ! 0L
expectMsgClass(classOf[Option[Long]])
}
// test the executor directly
within(10.seconds) {
executor ! AskExecution(3L)
expectMsgClass(classOf[Option[Long]])
}

Why is my Actor created 2 times

I wrote this code
class TestActor extends Actor {
override def preStart(): Unit = {
println("going to start my test actor")
}
override def postStop(): Unit = {
println("came inside stop")
}
def receive = {
case msg: TestMessage => sender ! s"Hello ${msg.name}"
}
}
object TestActor {
val props = Props(new TestActor)
case class TestMessage(name: String)
}
I call it using this client code
object MyApp extends App {
val ac = ActorSystem("TestActorSystem")
val a = new ClassA(ac).sayHello()
val b = new ClassB(ac).sayHello()
for {
msg1 <- a
msg2 <- b
} {
println(msg1)
println(msg1)
}
Await.result(ac.terminate(), Duration.Inf)
}
class ClassA(ac: ActorSystem) {
def sayHello(): Future[String] = {
implicit val timeout = Timeout(5 seconds)
val actor = ac.actorOf(TestActor.props)
val msg = actor ? TestActor.TestMessage("foo")
msg.map(_.asInstanceOf[String])
}
}
class ClassB(ac: ActorSystem) {
def sayHello() : Future[String] = {
implicit val timeout = Timeout(5 seconds)
val actor = ac.actorOf(TestActor.props)
val msg = actor ? TestActor.TestMessage("bar")
msg.map(_.asInstanceOf[String])
}
}
I see the output
going to start my test actor
going to start my test actor
Hello foo
Hello foo
came inside stop
came inside stop
My question is that in the companion object I had created the props object as a val and therefore there was only 1 val and that 1 val had 1 instance of new TestActor
In the client both classes used the same instance of actor system. Therefore there should have been only 1 actor and both messages from classA and ClassB should have gone to the same actor.
But it seems that both classes got their own Actor instances.
My question is that in the companion object I had created the props object as a val and therefore there was only 1 val and that 1 val had 1 instance of new TestActor
Not really. Yes, you define one val, but that val is a Props. The Props class is essentially a recipe for creating an actor. What you're defining is a single immutable recipe for creating a TestActor. This recipe can be used multiple times, which is what you're doing when you call ac.actorOf(TestActor.props) twice. Both of these calls use the same Props recipe to create a new TestActor; that is, you use the same recipe to create two TestActor instances.
To reuse a single TestActor, do what #mfirry suggested and create this actor outside of ClassA and ClassB. Here's one way to do that:
object MyApp extends App {
val ac = ActorSystem("TestActorSystem")
val testActor = ac.actorOf(TestActor.props)
val a = new ClassA(ac).sayHello(testActor)
val b = new ClassB(ac).sayHello(testActor)
for {
msg1 <- a
msg2 <- b
} {
println(msg1)
println(msg1)
}
Await.result(ac.terminate(), Duration.Inf)
}
class ClassA(ac: ActorSystem) {
def sayHello(actor: ActorRef): Future[String] = {
implicit val timeout = Timeout(5 seconds)
val msg = actor ? TestActor.TestMessage("foo")
msg.map(_.asInstanceOf[String])
}
}
class ClassB(ac: ActorSystem) {
def sayHello(actor: ActorRef): Future[String] = {
implicit val timeout = Timeout(5 seconds)
val msg = actor ? TestActor.TestMessage("bar")
msg.map(_.asInstanceOf[String])
}
}
This is caused by actorOf will create a new actor, so for twice actorOf it will create 2 TestActor. you can use actorSelection to avoid the second creation, like:
class ClassA(ac: ActorSystem) {
def sayHello(): Future[String] = {
implicit val timeout = Timeout(5 seconds)
val actor = ac.actorOf(Props[TestActor], "test")
println(actor.path)
val msg = actor ? TestMessage("foo")
msg.map(_.asInstanceOf[String])
}
}
class ClassB(ac: ActorSystem) {
def sayHello() : Future[String] = {
implicit val timeout = Timeout(5 seconds)
val actor = ac.actorSelection("akka://TestActorSystem/user/test")
val msg = actor ? TestMessage("bar")
msg.map(_.asInstanceOf[String])
}
}

Does Akka cache actor invocation?

I have the following code that I need to run around 100 times:
val system = ActorSystem("mySystem")
val myActorObject = system.actorOf(Props[MyActorClass], name = "myactor")
implicit val timeout = Timeout(60 seconds)
val future = myActorObject ? Request1
val result = Await.result(future, timeout.duration)
Question is: assuming the first two statements can be called just once, should I cache these variables or Akka does it?
Do not make the actor system creation and actor creation part of repetitive code. Once the actor is created. Using the ActorRef can be done as many times as possible.
val system = ActorSystem("mySystem")
val myActorObject = system.actorOf(Props[MyActorClass], name = "myactor")
Something like this
val futureList = for(_ <- 1 to 1000) yield {
implicit val timeout = Timeout(60 seconds)
val future = myActorObject ? Request1
}
val finalF = Future.sequence(futureList)
val result = Await.result(future, timeout.duration)
In play! (+2.5.x) you can get the system by injection. e.g.
#Singleton
class MyController #Inject() (system: ActorSystem) extends Controller {
val myActor = system.actorOf(MyActorClass.props, "myactor")
//...
}
Then you could have an end point to call the actor as many times as you want, for example
def sayHello(name: String) = Action.async {
(myActor ? name).map { message => Ok(message) }
}
The code inside your actor could be something like this
class MyActorClass extends Actor {
def receive = {
case name: String => sender() ! s"hello $name"
}
}
object MyActorClass {
def props: Props = Props(classOf[MyActorClass ])
}

How to add elements to Source dynamically?

I have example code to generate an unbound source and working with it:
object Main {
def main(args : Array[String]): Unit = {
implicit val system = ActorSystem("Sys")
import system.dispatcher
implicit val materializer = ActorFlowMaterializer()
val source: Source[String] = Source(() => {
Iterator.continually({ "message:" + ThreadLocalRandom.current().nextInt(10000)})
})
source.runForeach((item:String) => { println(item) })
.onComplete{ _ => system.shutdown() }
}
}
I want to create class which implements:
trait MySources {
def addToSource(item: String)
def getSource() : Source[String]
}
And I need use it with multiple threads, for example:
class MyThread(mySources: MySources) extends Thread {
override def run(): Unit = {
for(i <- 1 to 1000000) { // here will be infinite loop
mySources.addToSource(i.toString)
}
}
}
And expected full code:
object Main {
def main(args : Array[String]): Unit = {
implicit val system = ActorSystem("Sys")
import system.dispatcher
implicit val materializer = ActorFlowMaterializer()
val sources = new MySourcesImplementation()
for(i <- 1 to 100) {
(new MyThread(sources)).start()
}
val source = sources.getSource()
source.runForeach((item:String) => { println(item) })
.onComplete{ _ => system.shutdown() }
}
}
How to implement MySources?
One way to have a non-finite source is to use a special kind of actor as the source, one that mixes in the ActorPublisher trait. If you create one of those kinds of actors, and then wrap with a call to ActorPublisher.apply, you end up with a Reactive Streams Publisher instance and with that, you can use an apply from Source to generate a Source from it. After that, you just need to make sure your ActorPublisher class properly handles the Reactive Streams protocol for sending elements downstream and you are good to go. A very trivial example is as follows:
import akka.actor._
import akka.stream.actor._
import akka.stream.ActorFlowMaterializer
import akka.stream.scaladsl._
object DynamicSourceExample extends App{
implicit val system = ActorSystem("test")
implicit val materializer = ActorFlowMaterializer()
val actorRef = system.actorOf(Props[ActorBasedSource])
val pub = ActorPublisher[Int](actorRef)
Source(pub).
map(_ * 2).
runWith(Sink.foreach(println))
for(i <- 1 until 20){
actorRef ! i.toString
Thread.sleep(1000)
}
}
class ActorBasedSource extends Actor with ActorPublisher[Int]{
import ActorPublisherMessage._
var items:List[Int] = List.empty
def receive = {
case s:String =>
if (totalDemand == 0)
items = items :+ s.toInt
else
onNext(s.toInt)
case Request(demand) =>
if (demand > items.size){
items foreach (onNext)
items = List.empty
}
else{
val (send, keep) = items.splitAt(demand.toInt)
items = keep
send foreach (onNext)
}
case other =>
println(s"got other $other")
}
}
With Akka Streams 2 you can use a sourceQueue : How to create a Source that can receive elements later via a method call?
As I mention in this answer, the SourceQueue is the way to go, and since Akka 2.5 there is a handy method preMaterialize which eliminates the need to create a composite source first.
I give an example in my other answer.