0

I have an akka actor, and I would like to use a simple service inside that actor. That service should use the client side api's singleRequest method to fetch something from the local network.

My Actor:

package actor

import actor.WorkerActor._
import akka.actor.Actor
import service.HealthCheckService

import scala.concurrent.ExecutionContext

object WorkerActor {
  case object HealthCheck
}

class WorkerActor extends Actor {

  implicit val system = context.system
  implicit val ec: ExecutionContext = context.system.dispatcher

  val healthCheckService = new HealthCheckService()

  override def receive: Receive = {
    case HealthCheck => sender ! healthCheckService.execute()
  }
}

Here I created an ActorSystem and an ExecutionContext as well, so that my service can use it:

package service

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}

import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}

class HealthCheckService(implicit ec: ExecutionContext, implicit val system: ActorSystem) {


  def execute() = {
    val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

    and do something with the response....
  }
}

If I don't pass an executionContext into the service I get the error:

[error] Cannot find an implicit ExecutionContext. You might pass
[error] an (implicit ec: ExecutionContext) parameter to your method
[error] or import scala.concurrent.ExecutionContext.Implicits.global.

And if I don't pass an actorsystem into the service I get the error:

[error] could not find implicit value for parameter system: akka.actor.ActorSystem
[error] val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

Questions:

  • How should services be correctly used from an Actor?
  • Is it correct to pass around the ActorSystem and ExecutionContext, why doesn't it happen under the hood?
handris
  • 1,999
  • 8
  • 27
  • 41

1 Answers1

0

Http.apply signature is

def apply()(implicit system: ActorSystem): HttpExt

so you need to pass ActorSystem to it implicitly or explicitly. I do not see anything that requires ExecutionContext inside service, so suppose you do something with Future you get from singleRequest call. Any method on Future will require execution context.

So code is correct, but could be simplified a little:

class WorkerActor extends Actor {
  // you do not need to declare implicit val if you just need to pass it once
  val healthCheckService = new HealthCheckService(context.system)

  override def receive: Receive = {
    case HealthCheck => sender ! healthCheckService.execute()
  }
}

class HealthCheckService(implicit val system: ActorSystem) {
  // dispatcher is already implicit so you need just import it, not declare another val
  import system.dispatcher
  def execute() = {
    val responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://someRandom.url"))

    and do something with the response....
  }
}

Also, from your code for service I have an impression that you manipulate somehow with future, probably adding await (as soon as your service per your question does not really need ActorSystem), instead using akka and piping messages to actors from Future. Probably (as answer on you first question), you need to check later example of using singleRequest with actors from link to akka-http you added in question .

Evgeny
  • 1,760
  • 10
  • 11