5

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!!

gaston
  • 498
  • 7
  • 15
  • 5
    You don't need to create `ActorMaterializer` multiple time, you can create one instance of this class and pass this parameter to specific method/function/constructor, this approach works fine –  Oct 30 '16 at 12:09
  • Ok, thank you for the answer rukavitsya !! – gaston Oct 30 '16 at 16:23

0 Answers0