Skip to content
This repository has been archived by the owner on Nov 10, 2022. It is now read-only.

Comparision with Orbit #65

Open
domdorn opened this issue Mar 5, 2018 · 6 comments
Open

Comparision with Orbit #65

domdorn opened this issue Mar 5, 2018 · 6 comments

Comments

@domdorn
Copy link

domdorn commented Mar 5, 2018

Yesterday I stumbled upon Orbit https://github.com/orbit/orbit

What I really liked is the way of having a type-safe way to interact with an actor.. e.g. the Actors protocol is defined through an interface / a trait that I can apply to my ActorRef to have a type-safe way to interact with it.

Its basically, what I'm now doing in a manual way to interact with my actors from the outside world, where I create a service that has methods returning futures, and inside those methods I'm either just telling or asking and then mapping the expected messages back to some distinct types.

Couldn't we use this approach in Akka as well?

sealed trait GreetingResponse
case class HelloMsg(msg: String) extends GreetingResponse
case object GoAway extends GreetingResponse

sealed trait GreetingMessage
case class Greet(msg: String) extends GreetingMessage
case object SayBye extends GreetingMessage

trait Greeter extends ActorProtocol { 
   def greet(message: String): ActorAsk[GreetingMessage, GreetingResponse]
   def sayBye(): ActorTell[GreetingMessage]
} 

val myActor: ActorRef = ...

val typedActor = Typed(myActor, classOf[Greeter])

typedActor.greet("Hello!").flatMap { 
 case x@HelloMsg(msg) => typedActor.greet("oh, its nice to meet you too!")  
 case GoAway => typedActor.sayBye() 
 // compiler would tell me if I miss a branch.. 
} 

where ActorAsk and ActorTell are basically futures ?

@jrudolph
Copy link
Member

jrudolph commented Mar 5, 2018

Have you already looked at Akka Typed? What is missing that you are looking for?

@domdorn
Copy link
Author

domdorn commented Mar 5, 2018

From looking at the code there, it does not feel like I'm really working with Actors anymore, but just some behaviors flying around.

Creating a ActorSystem for a single actor/behavior also looks bad (and its one of the anti-patterns mentioned in the Akka Anti-Patterns talk) .. val system: ActorSystem[Greet] = ActorSystem(greeter, "hello") ... what if I have hundreds of different actors in my system... will I have hundred ActorSystems?

even then, it does not look like I'll have compile time support for working with the protocol of an actor.. or will my IDE be able to autocomplete the ask part this call or tell me which parameters are possible?
val future: Future[Greeted] = system ? (Greet("world", _))

At the moment it looks like this is a kind of mixture of akka-streams and FSM.. but it does not look or feel like Actors anymore..

I guess what I'm looking for is just a way to decorate a ActorRef with a defined protocol.. all the things with Behaviors, etc. feel quite overkill and not like "Akka" anymore. From this point of view, I really liked what I've seen on the Orbit webpage.

@rkuhn
Copy link
Contributor

rkuhn commented Apr 8, 2018

Actors always are characterised by their behavior, in akka-actor this is a PartialFunction[Any, Unit]. If you want to group related behaviors you put them into the same class or object, this goes for typed as well as untyped. It is true that in addition to adding a type parameter to ActorRef the new Behavior allows more flexibility, in particular concerning synchronous and deterministic testing. This was a primary design goal as I see it as the greatest weakness of akka-actor that all tests are necessarily non-deterministic.

BTW: it is not at all necessary to create one ActorSystem per Actor, that would be quite nonsensical ;-) You could have your guardian actor offer the service of creating actors for the outside world, or you could also write the whole program or component as one actor hierarchy—with proper supervision all the way to the top.

@jducoeur
Copy link

jducoeur commented Apr 9, 2018

BTW: it is not at all necessary to create one ActorSystem per Actor, that would be quite nonsensical

Y'all may want to spell this out more explicitly in the documentation somewhere -- the current docs left me scratching my head and wondering about this, because so many examples show "create an ActorSystem then create an Actor". That seemed odd, but it's the impression I was getting, especially because the ActorSystem is, itself, now typed.

Question: is it legit to pass ActorRefs between separate ActorSystems? I'm trying to understand whether it is necessary for an application to create its own user guardian, which is ultimately (if indirectly) responsible for creating all the other Actors, or whether an application can/should be composed of multiple ActorSystems in a single process.

I suspect the team finds this obvious one way or the other, but I didn't notice it discussed in the documentation, and it's really important. From traditional Akka, I would tend to expect that you should have a single ActorSystem in a process; given the constraints of Typed, that suggests that you must then create your own guardian, which provides typed APIs for creating all the subsidiary Actors. All of which makes sense, but as far as I can tell it never says that anywhere, and it's a huge difference from traditional Akka, where you routinely create stuff from the ActorSystem itself.

Basically, in traditional Akka you are (potentially) building a forest of many trees, all rooted in the built-in user guardian. It sounds like, in Akka Typed, you are usually building a single tree, rooted in your own user guardian. Is that correct? One way or t'other, it probably ought to be spelled out in the docs, in the section that compares Akka Typed with traditional Akka...

@patriknw
Copy link
Member

patriknw commented Apr 9, 2018

Thanks for highlighting the missing or misleading documentation around this. I created issue akka/akka#24867

Question: is it legit to pass ActorRefs between separate ActorSystems?

That is the same as for untyped. You can pass ActorRefs in messages. For the initial lookup you would use the receptionist instead of actor selection.

It would be wrong to pass an ActorRef as a direct in-memory reference between two actor systems running in the same jvm, and that is also invalid in untyped. If you for some reason run several actor systems in the same jvm, e.g. for testing, you should still retrieve and pass the actor references with the same mechanisms as you would if they were distributed.

it's a huge difference from traditional Akka, where you routinely create stuff from the ActorSystem itself

yes, system.actorOf is not supported when you have started the actor system with a custom user guardian, instead that should be replaced by context.spawn in the user guardian. However, if you have an existing untyped application and want to introduce a few typed actors you can still start the akka.actor.ActorSystem without a custom user guardian and then untyped actors can be started with system.actorOf. More about this in the Coexistence section of the docs.

@jducoeur
Copy link

jducoeur commented Apr 9, 2018

It would be wrong to pass an ActorRef as a direct in-memory reference between two actor systems running in the same jvm, and that is also invalid in untyped.

Okay, that's what I figured -- and once I realized that, I figured you pretty much had to create your own user guardian. But I wasn't certain. Good to know...

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants