I'm trying to realise the "actors fabric". An application include fabric-actor, which must spawn child actors on demand.
I tried to realise this as follows:
object BranchCreator {
final case class CreateBranche(name: String)
def apply(): Behavior[CreateBranche] = {
Behaviors.receiveMessage { (context, message) =>
context.spawn(new Branch(), message.name)
}
}
}
But method spawn is not available for context. Only "name" and "copy" are available for context.
Use Behaviors.receive instead of Behaviors.receiveMessage
As per documentation of Behaviors.receiveMessage:
Simplified version of Behaviors.Receive with only a single argument - the message to be handled. Useful for when the context is already accessible by other means, like being wrapped in an setup or similar.
[cut]
Related
We are building a event sourced system based on Akka-Typed. We quickly fall in a situation where our states requires many parameters passed as implicits parameters.
There is a solution on the style guide to use an enclosing class; https://doc.akka.io/docs/akka/current/typed/style-guide.html#passing-around-too-many-parameters.
However this is for "simple" behaviors, not for EventSourcedBehaviors. This technique of using a enclosing class that produce behaviors does not work for event sourced one because an event sourced behavior is made of one command handler and one event handler.
In our case we have a State trait that define one method to received commands and another to handle events. If we apply the enclosing class technique we have to create anonymous classes for all states, but those cannot be serialized.
object SampleEventSourced {
trait State extends CborSerializable {
def execute(cmd: Command): ReplyEffect
def apply(evt: Event): State
}
def apply(
persistenceId: PersistenceId,
config: Config,
): Behavior[Command] = {
EventSourcedBehavior
.withEnforcedReplies[Command, Event, State](
persistenceId,
new SampleEventSourced(config).empty(),
(state, cmd) => state.execute(cmd),
(state, evt) => state.apply(evt)
)// ...
}
}
class SampleEventSourced private(config: Config) {
import SampleEventSourced._
private def empty(): State = new State {
override def execute(cmd: Command): ReplyEffect = cmd match {
// ..
}
override def apply(evt: Event): State = evt match {
// ..
}
}
java.lang.IllegalArgumentException: Empty State [org.acme.SampleEventSourced$$anon$1#36d7d2fe] isn't serializable.
One solution would be to duplicate the creation of the event sourced behavior in each "state" method. But that will produce a lot of duplication.
object SampleEventSourced {
def apply(
persistenceId: PersistenceId,
config: Config,
): Behavior[Command] = new SampleEventSourced(config).empty()
}
class SampleEventSourced private(config: Config) {
import SampleEventSourced._
private def empty(): Behavior[Command] = EventSourcedBehavior
.withEnforcedReplies[Command, Event, State](
persistenceId,
new State(),
(state, cmd) => state.execute(cmd),
(state, evt) => state.apply(evt)
)// ...
}
Another would be to create concrete subclasses of State but we will have to pass the parameters across all of those states.
object SampleEventSourced {
class EmptyState extends State(config:Config, otherUselessParameter:Any) {
// ...
override def apply(evt: Event): evt match {
case _ => new OtherState(config, otherUselessParameter)
}
}
class OtherState extends State(config:Config, veryImportantParameter:Any) {
// ..
}
}
Putting those state classes inside the enclosing class won't work because those non-static inner classes cannot be de-serialized.
So, what's your solution for this case, how do you deal with EventSourcedBehavior with states that require many parameters ?
The problem is that that jackson-cbor, on top of being reflection based, isn't that effective at serializing things done in an idiomatic Scala way (the only real point in its favor is that it's better than Java serialization).
So the immediately apparent solution is to:
model the state as an Algebraic Data Type (generally a sealed trait extended by case classes and maybe a case object for the empty/initial state case).
don't serialize them via Jackson, but use a native-to-Scala serializer (e.g. play-json, circe, etc.) and an Akka serializer leveraging that serializer; it's likely easier to define a marker trait (e.g. CirceSerializable) so that in the configuration you only have to worry about one binding. Events & state will want to be marked with that trait: commands and their replies (at least the ones that could be sent over the network might also as well).
One subtlety to be aware of when defining your serializer is that, the native-to-Scala serializers will generally use some form of typeclass derivation at compile time, but this will be complicated if there's a need to serialize ActorRef, as a serializer for ActorRef is best done with the aid of the ActorSystem (EntityRef can now be inspected for serialization, and conceptually makes more sense for persistence, given the lifecycle, but that's going to be fairly custom): you'll therefore probably want to delay derivation of the ActorRef serializer/deserializer until the ActorSystem starts up and also delay derivation of the events/state/commands/replies containing ActorRefs until after then.
I'd probably tend to make the handler for each event a method in the sealed trait without letting the state have any knowledge of how events are reified. The benefit of this is that you can unit test the state transitions without needing events or commands.
case class ItemAdded(name: String) extends Event
sealed trait State {
def items: Set[String]
def addItem(name: String): State.NonEmpty
}
object State {
case object Empty extends State {
def items: Set[String] = Set.empty
def addItem(name: String): NonEmpty = NonEmpty(Set(name))
}
case class NonEmpty(items: Set[String]) extends State {
def addItem(name: String): NonEmpty = copy(items = items + name)
}
}
Then your event handler is pretty thin
(state, evt) => {
evt match {
case ItemAdded(name) => state.addItem(name)
}
}
Depending on how much validation your command handlers take on, those can get complex. The operative principle is that commands are interpreted into zero-or-more events, and events are interpreted into operations (methods on state which result in a new state) on the state. The state should thus have sufficient query methods (e.g. items) to allow the command-handler to consume a state.
Title is self-explanatory, I want to be able to send a message to a parent actor (meaning I want parent's ActorRef). In Akka Classic (untyped), the ActorRef for a parent actor can be obtained from the child's ActorContext via:
context.parent
(see, for instance, this question (in Java)).
However, the akka.actor.typed.scaladsl.ActorContext in Akka Typed does not expose an ActorRef for the parent. Is there an idiomatic means in Scala to obtain an ActorRef for the parent actor?
TLDR:
Inject the parent actor reference into the child when creating it.
Akka Typed enforces strict protocols, so you need to make it absolutely clear that "this actor talks to another actor". The accepted answer is a workaround (casting to classic and using the parent), but has its downsides: now you do not enforce types anymore.
Here is some code that should get you started. See how all the types are enforced. You can model the traits differently, but you should get the drift:
object ParentActor {
sealed trait Command
case class DoSomething() extends Command
// you do not have to do this, but creating another trait
// allows you to narrow the amount of messages the parent can receive from the child
sealed trait ChildNotification extends Command
case class MessageFromChild() extends ChildNotification
def apply(): Behavior[Command] = {
Behaviors.receive( (context, message) =>
message match {
case DoSomething() =>
// create a child that knows about its parent
context.spawn(ChildActor(context.self), "child")
Behaviors.same
case MessageFromChild() =>
context.log.info("I received a message from my child")
Behaviors.same
})
}
}
object ChildActor {
sealed trait Command
case class Work() extends Command
// inject the parent here (or any other actor that matches the signature)
def apply(parent: ActorRef[ParentActor.ChildNotification]): Behavior[Command] = {
Behaviors.receive( (context, message) =>
message match {
case Work() =>
// send message to parent actor (or any other actor with that type)
parent ! ParentActor.MessageFromChild()
Behaviors.same
})
}
}
By the way, I am using the "functional" syntax of akka typed, but you can use the more "object-oriented" syntax as well. It follows the same approach.
If you're in typed Akka, the only [Scala] type that could encompass ActorRefs of all possible parent actors is ActorRef[Nothing], which is an ActorRef you can't send messages to, so that's of limited utility.
At least for as long as the classic APIs exist:
import akka.actor.typed.scaladsl.adapter._
type ClassicActorRef = akka.actor.ActorRef
val parentActorRef = context.toClassic.parent
This will be an untyped ActorRef, i.e. you're free to send messages which the parent actor will never accept.
If you want a typed reference to an actor's parent, you'll need to embed that when spawning the child actor, just as if you want a typed reference to the sender of the current message you need to embed replyTos in your protocol.
(context.sender is absent in the typed ActorContext for the same reason that context.parent is absent; the workaround for replicating classic context.sender is analogous: context.toClassic.sender)
The akka documentation is clearly stated that it is dangerous to create an actor within an actor like this:
class ActorA extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA))
}}
I understand that the Actor's apply method is accepting this reference of the creating actor. yet I couldn't understand (nor couldn't find any example) why this is harmful and what issues it can cause?
Let's tweak your example a little bit
class ActorA(str:String) extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA("hidden")))
}}
Most of the common use case of using actors are to handle failover and supervision, shen an actor fails and needs to be restarted, the actor system needs to know how to do that. When you use Props(Props(new ActorA)), you've hidden the parameter value of "hidden" by handling it yourself.
Rather than doing that if instead, you declare how to create instances of the actor, the actor system will know exactly what it needs to do when recreating an actor -
i.e. create an instance of ActorA with a constructor argument of "hidden".
Even with your example of Actor without param
context.actorOf(Props(new ActorA))
this way of instantiating actors within another actor is not recommended because it encourages to close over the enclosing scope, resulting in non-serializable Props and possibly race conditions (breaking the actor encapsulation).
I believe we are confusing creation and declaration. The doc says that
Declaring one actor within another is very dangerous and breaks actor encapsulation. Never pass an actor’s this reference into Props!
So the problem is declaration, not creation!
Let's look at Java's:
public class MyActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK", getSelf());
}
class MyOtherActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK-Inner", getSelf());
}
}
}
Now, if MyOtherActor was a normal class, we'd be able to instantiate it only from an instance of MyActor:
MyActor actor = new MyActor();
MyActor.MyOtherActor otherActor = actor.new MyOtherActor();
Which means that the constructor for MyOtherActor depends on the instance of MyActor!
Now, if Props are supposed to contain the "factory" of the actor. They need a factory method. If our MyOtherActor is declared as we did here, then our props would look like this (ish):
MyActor actor = ??? // how did you even get a reference to the actor and not the actorRef in the first place!
Props otherActorProps = Props.create(MyActor.MyOtherActor.class, () -> actor.new MyOtherActor());
And bang, here comes the kicker! Now your otherActorProps contains a reference to actor, i.e. you have closed over mutable state! If for whatever reason actor "dies", your props will still be referencing it, causing all sort of weirdness.
There is also the issue of how you get a reference to the actor in the first place, and not it's actorRef
IMHO, that's what the documentation is referring to, and not the fact of "creating" (i.e. instantiating, spawning) an actor within another one: that's absolutely normal and it's a routine operation of akka (that's why you can do getContext().actorOf(..) as well as actorSystem.actorOf(...)
The warning is there in the documentation because it's easy to accidentally close over the creating actor's state, including its this pointer (which you should never use in actor-based code).
In my experience, I've usually seen a props method put into an actor's companion object:
object ActorA {
def props() = Props(new ActorA)
}
Doing it that way ensures the returned Props isn't closing over an actor's state.
class ActorB extends Actor {
def receive = {
case _ =>
val actorB = context.actorOf(ActorA.props)
...
}
}
It's not as big of a possibility for actors that don't take constructor parameters, but once parameters come into play you need to be careful about closing over internal state.
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) = {...}
}
Lets say I have some commonly used by other actors service-layer actor. For example, an registry service that stores and retrieves domain objects:
case class DomainObject(id: UUID)
class Registry extends akka.actor.Actor {
def receive: Receive = {
case o: DomainObject => store(o) // save or update object
case id: UUID => sender ! retrieve(id) // retrieve object and send it back
}
}
I do not want to explicitly pass instance of such registry into all actors who may use it. Instead of it, I want them to be able to somehow 'locate' it.
For this I can think of two solutions:
Identify message: each registry user actor knows registry actor name from some configuration and able to sent identification message to it. After AgentIdentity message is received back we are good to go:
val registryName = ... // some name
val registryId = ... // some id
var registry = _
def preStart() {
context.actorSelection(registryName) ! Identify(registryId)
}
def receive: Receive = {
case ActorIdentity(`registryId`, ref) => registry = ref
}
I do not like this way because right after user actor initialisation there is a phase when we do not know if there is a registry in system et all and thus do not know will we ever be able to operate or not.
Akka Extensions: I can create an extension which would:
a. create instance of Registry actor in given Actor System on initialization;
b. return this actor to user who needs it via some method in Extension.
object RegistryKey extends ExtensionKey[RegistryExtension]
class RegistryExtesion(system: ExtendedActorSystem) extends RegistryKey {
val registry = system.actorOf(Props[Registry], "registry")
}
The question is: which method is better and are Akka Extesions can be used for this at all?
I think the extension idea is a good one as long as your registry actor is always going to be in the same ActorSystem.
Alternatively, using actorSelection (adapted from Remote Lookup):
class RegistryClient extends Actor {
val path = "/path/to/registry/actor"
context.setReceiveTimeout(3.seconds)
def sendIdentifyRequest(): Unit =
context.actorSelection(path) ! Identify(path)
def receive = {
case ActorIdentity(`path`, Some(ref)) ⇒
context.setReceiveTimeout(Duration.Undefined)
context.become(active(ref))
case ActorIdentity(`path`, None) ⇒
throw new RuntimeException("Registry not found")
case ReceiveTimeout ⇒ sendIdentifyRequest()
}
def active(registry: ActorRef): Actor.Receive = {
// use the registry
}
}
This will work for remote or local actors.
Let's look at the extension solution. Actors are created asynchronously. Therefore your extension constructor won't fail when calling actorOf if the actor fails to initialize.
If you want to know for sure that the actor failed to initialize then one way to know is to ask the actor something that it will respond to and Await a response. The Await will throw a TimeoutException if the actor fails to respond.
class RegistryExtension(system: ExtendedActorSystem) extends Extension {
val registry = system.actorOf(Props[Registry], "registry")
implicit val timeout: Timeout = Timeout(500.millis)
val f = registry ? "ping" // Registry should case "ping" => "pong"
Await.result(f, 500.millis) // Will throw a TimeoutException if registry fails
// to respond
}
The TimeoutException will get thrown when you call RegistryExtension(system).registry the first time.
How about the Cake Pattern or a Dependency Injection library such as subcut.
Derek Wyatt mentions DI in his book 'Akka Concurrency' instead of using too much actorFor to look up actors:
http://www.artima.com/forums/flat.jsp?forum=289&thread=347118