Get context from Main Actor in Akka - scala

I'm attempting to shoot fire off a POST request like the one in the Akka docs showed here. http://doc.akka.io/docs/akka-http/current/scala/http/client-side/request-level.html#request-level-api
However, I'm trying to do it as inside of another defined class. If I try to add in anything that requires the Actor context like val http = HTTP(context.system) I get an error. How can I pass in the context into the class I'm trying to make the POST request from?
trait CustomerProfilesComponent {
def customerProfileManager: CustomerService.Async
}
object DefaultCustomerProfiles {
private case class ProfileUpdateData(path: Seq[String], data: JsObject, metadata: JsObject)
}
trait DefaultCustomerProfiles extends CustomerProfilesComponent {
self: DatabaseComponent with SourceVersionComponent with ExecutionContextComponent =>
import DefaultCustomerProfiles._
lazy val customerProfileManager = new CustomerService.Async {
import db.api._
import AvroConverter._
override def getVersion : Future[AvroVersion] = {
Future.successful(toAvro(sourceVersion))
}
}

What you need is actually an actor system. Posting from the akka-http docs:
The request-level API is implemented on top of a connection pool that is shared inside the ActorSystem.
There are two usage scenarios for the request API:
use it within an actor - when you can get the actor system via the actor context (like you have tried, but since you are not inside an actor, you don't have an actor context available)
use it outside an actor (your case) - when you can get the actor system by providing it as an dependency (either via class/method params or implicit params)
I hope this is helpful.

Related

Looking for an abstraction that allows a class to spawn actors

I have a class that offers different kinds of Sources to it's clients. When a Source is run, an actor should be spawned that feeds new entries into the respective stream. So my class needs to be able to spawn actors. I know of two ways to do this: Using the ActorContext of another actor or using the ActorSystem. Is there a common abstraction for the ability to spawn new actors so I could inject a helper into my class that just allows it to spawn actors if required regardless of how it is done?
I created an ActorSpawner interface for this purpose and it worked pretty well so far:
trait ActorSpawner {
def spawn[T](behavior: Behavior[T]): ActorRef[T]
def spawn[T](behavior: Behavior[T], name: String): ActorRef[T]
}
However, since I upgraded to Akka 2.6 I frequently get these error messages:
ERROR akka.actor.SupervisorStrategy - Unsupported access to ActorContext from the outside
of Actor[akka://...]. No message is currently processed by the actor, but ActorContext was called from Thread[...]
It seems this wasn't a problem before the upgrade but now I'm wondering whether what I was doing was advisable anyway or if this is kind of an anti-pattern.
In Typed, with the exception of the guardian actor (the one created when creating the ActorSystem), actors can only be spawned by other actors.
There are still plenty of cases where code executing outside of an actor wants to spawn an actor. For this, you can send a message to an actor and have that actor spawn an actor with the desired behavior.
If you have an actor whose sole purpose is spawning other actors, Akka includes the SpawnProtocol, which is compatible with the ask pattern:
trait ActorSpawner {
def spawn[T](behavior: Behavior[T], name: String): Future[ActorRef[T]]
def spawn[T](behavior: Behavior[T]): Future[ActorRef[T]] = spawn(behavior, "")
}
def spawnerFor(spawningActor: ActorRef[SpawnProtocol.Spawn])(implicit system: ActorSystem[Nothing]): ActorSpawner = {
import system.executionContext
import akka.actor.typed.scaladsl.AskPattern._
implicit val timeout = Timeout(10.seconds) // or whatever, can also make this an arg
new ActorSpawner {
def spawn[T](behavior: Behavior[T], name: String): Future[ActorRef[T]] =
spawningActor.ask(SpawnProtocol.Spawn(behavior, name, Props.empty, _))
}
}
If your guardian actor happens to only spawn other actors on demand, it can implement SpawnProtocol, in which case the ActorSystem is itself an ActorRef[SpawnProtocol.Spawn], so that could be further simplified to
def spawnerFor(system: ActorSystem[SpawnProtocol.Spawn]): ActorSpawner = {
import system.executionContext
import akka.actor.typed.scaladsl.AskPattern._
implicit val timeout = Timeout(10.seconds)
implicit val scheduler = system.scheduler
new ActorSpawner {
def spawn[T](behavior: Behavior[T], name: String): Future[ActorRef[T]] =
system.ask(SpawnProtocol.Spawn(behavior, name, Props.empty, _))
}
}
I know of two ways to do this: Using the ActorContext of another actor or using the ActorSystem
I think this is true for the Classic (i.e. untyped) Actor API and the common abstraction is akka.actor.ActorRefFactory which both akka.actor.ActorSystem and akka.actor.ActorContext extend. This is where def actorOf(props: Props): ActorRef lives for creating new actors.
In the new typed Actor API this is no longer the case. You can't create an actor from akka.actor.typed.ActorSystem, you can only create it from akka.actor.typed.scaladsl/javadsl.ActorContext with spawn* family of methods with the exception of the guardian/root actor of given actor system, which you can create by ActorSystem(guardianBehavior: Behavior[T], name: String) and friends in Scala or with ActorSystem.create(...) equivalent in Java.
The ActorContext should only be accessed from a message processing thread of the actor that owes it or from setup method and the runtime check that produces the error log is in place since 2.6.6. You probably call the object from somewhere else. Perhaps this post will be useful in tracking where exactly: https://discuss.lightbend.com/t/akka-2-6-6-context-log-error-string-failed/6708/2

Akka HTTP: How to split routes with actors

I have an old Scala/Akka Http project that I'm trying to simplify and refactor. I was wondering if there's a better way to organize routes and perhaps split them across actors. Here's what I have at the moment (far from ideal):
```
object MyAPI {
def props(): Props = Props(new MyAPI())
val routes = pathPrefix("api") {
pathPrefix("1") {
SomeActor.route //More routes can be appended here using ~
}
}
}
final class MyAPI extends Actor with ActorLogging {
implicit lazy val materializer = ActorMaterializer()
implicit lazy val executionContext = context.dispatcher
Http(context.system)
.bindAndHandleAsync(Route.asyncHandler(MyAPI.routes), MyHttpServer.httpServerHostName, MyHttpServer.httpServerPort)
.pipeTo(self)
override def receive: Receive = {
case serverBinding: ServerBinding =>
log.info(s"Server started on ${serverBinding.localAddress}")
context.become(Actor.emptyBehavior)
case Status.Failure(t) =>
log.error(t, "Error binding to network interface")
context.stop(self)
}
}
```
```
object SomeActor {
def props(): Props = Props[SomeActor]
val route = get {
pathPrefix("actor") {
pathEnd {
complete("Completed") //Is there a clean way 'ask' the actor below?
}
}
}
}
class SomeActor extends Actor with ActorLogging {
implicit lazy val executionContext = context.dispatcher;
override def receive: Receive = {
//receive and process messages here
}
```
So, my question is - is there a clean way to structure and refactor routes instead of lumping them together in one large route definition? I could perhaps create a hierarchy of actors (routers) and the main route definition just delegates it to the routers and we incrementally add more details as we go deeper in the actor hierarchy. But is there a generally accepted patter or two to organize routes?
I would like to suggest you on the basis of the functionality you can have as many actors you you want, but create one supervisor actors which will keep watch on each child actor. And all the supervision strategies should be written into the supervisor itself, and all the msg you gonna sent to the actors should be forwarded by the supervisor.
As soon as you get the data from the end point, may be get or post method take the data into someRequest case class. Then sent it to some handleReq() method. And then do your processing make traits on functionality basis.
You can structure project something like this.
src/
actor//all the actors will be in this package
model// all the case classes and constants
repo// all the db related function you can do here
service// all your routes and endPoint functions
Now you can have package util where all the utilities trait you can put which will be used by any of the actor, or service may be you have lots of validations you can have a package named validator.
The structure is depends on your business. I think it would help.

Akka HTTP Code/Structural Patterns

I am just starting with Akka Http (and Scala) and was wondering if there are any well-defined patterns for structuring Akka code. In particular, I am looking for structural patterns for composing/aggregating routes dynamically. In particular, I'm looking for a solution similar to the below pseudocode:
trait MyActor extends Actor {
val myRouter: ActorRef = context.actorOf(FromConfig.props(Props[MyWorker]), "Worker")
val myRoute = .... //route definition for this trait
}
trait MySecondActor extends Actor {
val mySecondRouter: ActorRef = context.actorOf(FromConfig.props(Props[MySecondWorker]), "SecondWorker")
val myRoute = .... //route definition for this trait
}
Then, in my main server just mix in the traits to get both actors and routes automagically:
class HttpServer extends SomeTrait with MyActor with MySecondActor {
.....
.....
}
There are some obvious problems with the above pattern including:
All traits inherit from Actor and then mix into the same class - not sure what the final behaviour will be.
The HttpServer class itself becomes an actor and cannot be instantiated by new HttpServer()
The routes are not concatinated.
What I'm looking for is a pattern that:
Allows me to separate routing logic in various packages and preferable bundle it with corresponding actors.
Make routes dynamic and discoverable instead of specifying them at boot time.
I came across the following two on StackOverflow but was wondering if there's a better approach and a well-defined pattern:
akka-http with multiple route configurations (This isn't really dynamic)
How to aggregate akka-http routes using a trait? (Old question using reflection)
Thanks!
When using akka-http you usually don't need actors to implement the routing. Actors are usually only used to access the business logic asynchronously. Let me give you an example on how to structure your code with predefined routes. This is the pattern I learned from Heiko Seeberger.
First create an object creating your routes:
object Api {
def route: Route = {
import import akka.http.scaladsl.server.Directives._
pathSingleSlash {
get {
complete(StatusCodes.OK)
}
}
}
}
If you need an actor to access your business logic you can pass it as parameter to the route method. Remember to use the ask pattern, when interacting with actor during request handling.
Than you create a Root actor which creates your Api:
final class Root extends Actor with ActorLogging {
Http(context.system)
.bindAndHandle(Api.route, "0.0.0.0", 8000)
.pipeTo(self)
override def receive: Receive = {
case s: ServerBinding =>
log.info(s"Listening to ${s.localAddress}")
context.become(Actor.emptyBehavior)
case Status.Failure(t) =>
log.error(t, "Error binding to network interface")
context.stop(self)
}
}
Finally you need some main method to create the actor system and the Root actor:
object Main {
def main(args: Array[String]): Unit = {
val system = ActorSystem("user-api")
system.actorOf(Props(new Root))
Await.ready(system.whenTerminated, Duration.Inf)
}
}
So this would be my take on best practices for defining akka-http routes. What is not covered in my answer is how to dynamically discover routes, but to be honest, I fail to see the use case here. Usually your system should have some well defined end points. How would users know which endpoints they can talk to if even the system does not know which endpoints it will serve at startup time?

How to pass a class as a parameter for instantiation in Scala

I am trying to refactor an Akka application from a single tier to multi-tier structure with akka clustering (http://doc.akka.io/docs/akka/2.3.9/scala/cluster-usage.html). Within the application are some actors that have a parameterized default constructor, e.g.
class MyActor(someParam: boolean = true) extends Actor {
def receive = { /* message handling here... */ }
}
I am now trying to create a generic router actor that will route to a node with a specific node. The cluster configuration is working based of the example on the akka site, and I can create a router in 1 role that routes to the actor in another role:
class MyActorProxy extends Actor {
val workerRouter = context.actorOf(FromConfig.props(Props(classOf[MyActor]), name = "workerRouter")
def receive = {
case msg: Any =>
val currentSender = sender()
workerRouter.tell(msg, currentSender)
}
}
This method works as needed. However, I need to go and create a handful of proxy classes with the same functionality, and it's painful. I'm trying to make it work better, and limited scala experience is making it difficult. Here's what I am trying to do:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props(classOf[T])),name=routerPath)
def receive = {
case msg: Any => {
val currentSender = sender()
router.tell(msg,currentSender)
}
}
}
class MyActorProxy extends RouterProxy[MyActor](routerPath = "myActorRouter")
Have come up with this by reading through some scala docs and through stackoverflow, but can't seem to get it right - this approach doesn't let me create the props for the actor. I've seen How to instantiate an instance of type represented by type parameter in Scala and I think that the type information is being lost (type erasure).
How would I go about passing an actor class to the router proxy to allow for router initialization?
This is the error I get during compilation, while initializing the router:
class type required but T found
edit
Background for using a generic proxy router
The reason for this approach is to refactor the application for both single tier and multi-tier architecture. When running multi-tier, I want to skip initializing any "heavy" actors. Given I have the following config on a frontend node:
akka.actor.deployment {
/workerRouter {
routee.paths = ["/user/myActor"]
cluster.use-role = backend
}
}
akka.cluster.roles = [frontend]
and the backend node has roles of [backend], then when I start up frontend nodes, MyActor will not be initialized. MyActor is an example of 1 of many actors that are supervisors / managers. Each 1 of them might initialize a few other actors in turn (sometimes with routers). What I'm trying to do is refactor the application so I can run lightweight frontend nodes in a different tier to resource heavy backend nodes if I need to, but also still have the ability to run all on a single node. By this approach, I can add in initialization for heavy managers into my application bootstrap and add a role and it becomes a multifunctional app without needing recoding.
edit 2
I am able to get the application to work as expected if the class constructor doesn't take any arguments.
MyActor extends Actor { /* ... */ }
And then in my abstract class:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props[T]),name = routerPath)
}
Props[MyActor] works fine for a parameterless actor, but Props(classOf[T]) looses the type.
You don't actually have to define another class for the router, you can do it all through your configuration file:
val myActorRouter = system.actorOf(Props[MyActor]
.withRouter(FromConfig())
,"workerRouter")
Where "workerRouter" is defined in your application.conf file like this:
akka.actor.deployment {
/workerRouter {
router = round-robin
nr-of-instances = 5
}
}
You can also configure it all through code if you have a pretty simple configuration:
val myActorRouter = system.actorOf(Props[MyActor].withRouter(
RoundRobinRouter(nrOfInstances = 5)))
Either way you end up with myActorRouter as an actor ref you can send messages to. In the background the Akka system has created a pool of MyActor actors and forwards the messages to them. The router takes itself out of the response so you don't need to spoof the sender like you've done: when a routee sends a message to sender it goes directly back to the actor that sent the message to the router.

How to get a reference to an existing ActorSystem in Akka?

is it possible in Akka (scala) to get a reference to an existing ActorSystem?
I am working on a Spray application with another Actor for DB. I am also extending Directives to have an object per path. the directives are not actors by themselves, but they need to pass messages to the DBActor. here:
class HttpActor extends Actor with HttpService {
val actorRefFactory = context
def receive = runRoute(
IndexService.route ~
HostsService.route
)
}
object HostsService extends Directives{
def route(implicit dm: DetachMagnet2) = {
path("hosts") {
get {
detach() {
**dbActor ! CreateHost**
complete("get me hosts!")
}
} ~
post {
detach() {
entity(as[String]) { payload =>
complete(s"post hosts $payload")
}
}
}
}
}
}
is there a way for HostsService to discover the ActorSystem itself so he can find the DBActor, or must HttpActor pass it in? the latter seems less elegant, as it HostsService will need to become a class (not an object), so no longer a singleton.
From here:
there was a ticket for creating such a registry, but we were not
satisfied with what we got when trying to specify the semantics in
detail. One part is that we removed all global state so that different
parts of an application can use Akka without having to worry about
each other and a global feature would break this. Another is that it
would encourage get-or-create usage—my pet peeve—which would make the
semantics unclear: you give a name and a config, but if the name
already exists you potentially get back a differently configured
system (which is usually quite fatal).
There is nothing stopping you from putting a hashmap in some central
place of your application, (pre-)populate that with the actor systems
you need and be done, that's basically a one-liner (which is another
reason for not including it in Akka, because instead of a simple
solution to a very narrow problem we'd have to think of a solution to
a much more generic problem)
In your case, it's better to pass your system implicitly to the route function:
class HttpActor extends Actor with HttpService {
implicit val actorRefFactory = context
def receive = runRoute(
IndexService.route ~
HostsService.route
)
}
object HostsService extends Directives {
def route(implicit dm: DetachMagnet2, as: ActorContext) = {...}
}