Akka Ask Pattern with many types of responses - scala

I am writing a program that has to interact with a library that was implemented using Akka. In detail, this library exposes an Actor as endpoint.
As far as I know and as it is explained in the book Applied Akka Pattern, the best way to interact with an Actor system from the outside is using the Ask Pattern.
The library I have to use exposes an actor Main that accepts a Create message. In response to this message, it can respond with two different messages to the caller, CreateAck and CreateNack(error).
The code I am using is more or less the following.
implicit val timeout = Timeout(5 seconds)
def create() = (mainActor ? Create).mapTo[???]
The problem is clearly that I do not know which kind of type I have to use in mapTo function, instead of ???.
Am I using the right approach? Is there any other useful pattern to access to an Actor System from an outside program that does not use Actors?

In general it's best to leave Actors to talk between Actors, you'd simply receive a response then - simple.
If you indeed have to integrate them with the "outside", the ask pattern is fine indeed. Please note though that if you're doing this inside an Actor, this perhaps isn't the best way to go about it.
If there's a number of unrelated response types I'd suggest:
(1) Make such common type; this can be as simple as :
sealed trait CreationResponse
final case object CreatedThing extends CreationResponse
final case class FailedCreationOfThing(t: Throwable) extends CreationResponse
final case class SomethingElse...(...) extends CreationResponse
which makes the protocol understandable, and trackable. I recommend this as it's explicit and helps in understanding what's going on.
(2) For completely unrelated types simply collecting over the future would work by the way, without doing the mapTo:
val res: Future[...] = (bob ? CreateThing) collect {
case t: ThatWorked => t // or transform it
case nope: Nope => nope // or transform it to a different value
}
This would work fine type wise if the results, t and nope have a common super type, that type would then be the ... in the result Future. If a message comes back and does not match any case it'd be a match error; you could add a case _ => whatever then for example, OR it would point to a programming error.

See if CreateAck or CreateNack(error) inherit from any sort of class or object. If thats the case you can use the parent class or object in the .mapTo[CreateResultType].
Another solution is to use .mapTo[Any] and use a match case to find the resulting type.

Related

Akka Actors: ask pattern vs Promise

Lately I've found myself wrapping actors in classes so that I get back a little of the typesafety I lose when dealing with ActorRefs.
The problem is, at the end, that not only I need to send a specific message, I also need to cast the response to the expected result.
So I thought that I could send messages to actors that contain Promise so that they could report the result eventually.
Is that a bad idea? It looks pretty neat to me... Is typesafe and works just as good. Why hasn't anyone come with the idea? Is there anything wrong with it that I haven't noticed?
ask pattern based solution
case class GetUser(id:Long)
(actorRef ! GetUser(1l)).mapTo[User]
class UserRepoActor extends Actor{
def receive={
case GetUser(id)=>
sender() ! getUser(id)
}
...
}
Promise based solution
case class GetUser(id: Long, resp: Promise[User])
val req = GetUser(1l,Promise())
actorRef ! req
req.resp.future // No casting!!
class UserRepoActor extends Actor{
def receive={
case GetUser(id,resp)=>
response.success(getUser(id))
}
...
}
There is nothing wrong. Very close approach is used in akka typed with the only difference: a single-use ActorRef[T] is being sent instead of Promise[T]
Promises won't work in distributed actor system.
At least, without additional efforts for that.
Ask pattern is definitely better.
1) Actors are supposed to share no state and interact with the outer world via messages. Fulfilling the promise is actually a mutating shared variable
2) Passing the stateful objects into actor's creator (e.g. promise) breaks actor's lifecycle in case of restarts
So promise-based approach works in simple cases. But if you use it just like that probably you don't need such complicated stuff like akka at all?

Scala - "pattern matching results in loosened type guarantees"?

Out of a paper by Eugene Burmako:
In Akka, a [...], actors typically interact using an untyped tell method. Since actors are able to send messages of arbitrary types to one another, type information is lost on the receiver side, and can typically only be recovered using pattern matching, loosening type guarantees.
What guarantees is he referring to, here, and why does pattern matching weaken them?
A Spoty Spot's answer tells you what guarantees are lost, but the answer for "why does pattern matching weaken them" is that it doesn't. You misparsed the sentence slightly. Instead of
pattern matching, loosening type guarantees
read it as
type information is lost on the receiver side, and can typically only be recovered using pattern matching, loosening type guarantees
"and can typically only be recovered..." is a parenthetical.
Here is a simple akka example (from: here)
import akka.actor._
class HelloActor(myName: String) extends Actor {
def receive = {
case "hello" => println("hello from %s".format(myName))
case _ => println("'huh?', said %s".format(myName))
}
}
object Main extends App {
val system = ActorSystem("HelloSystem")
val helloActor = system.actorOf(Props(new HelloActor("Fred")), name ="helloactor")
helloActor ! "hello"
helloActor ! "buenos dias"
}
The receive function in the HelloActor takes an Any type. (Technically it is a partial function from Any to Unit). This means to understand its type we need to pattern match. I could send an Int to the HelloActor and the compiler wouldn't stop me. If I simply had a normal function that took in a string then the compiler would detect that. This lack of type safety is what I believe the quote is referring to.
There are typed akka actors but I have never used them and am not sure what they entail.

Untyped vs TypedActors - why use untyped?

I am trying to understand why one would use untyped actors over typed actors.
I have read several posts on this, some of them below:
What is the difference between Typed and UnTyped Actors in Akka? When to use what?
http://letitcrash.com/post/19074284309/when-to-use-typedactors
I am interested in understanding why untyped actors are better in the context of:
a web server,
A distributed architecture
Scalability,
Interoperability with applications written in other programming
languages.
I am aware, that untyped actors are better in the context of FSM because of the become/unbecome functionality.
I can see the possibilities of untyped in a load balancer, as it does not have to be aware of the contents of the messages, but just forward them to other actors. However this could be implemented in a typedactor as well.
Can someone come up with a few use case in the areas mentioned above, where untyped actors are "better"?
There is a generic disadvantage for type actors: they are hard to extend. When you use normal traits you can easily combine them to build object that implements both interfaces
trait One {
def callOne(arg : String)
}
trait Two {
def callTwo(arg : Double)
}
trait Both extends One with Two
The Both trait supports two calls combined from two traits.
If you usage actor approach that process messages instead of making direct calls you is still capable with extending interfaces refusing type safety as price.
trait One {
val receiveOne : PartialFunction[String,Unit] = {
case msg : String => ()
}
}
trait Two {
val receiveTwo : PartialFunction[Double, Unit] = {
case msg : Double => ()
}
}
trait Both extends One with Two {
val receive : PartialFunction[Any, Unit] = receiveOne orElse receiveTwo
}
The receive value in Both trait combines two partial functions. The first accepts only Strings, the second - only Doubles. They have single common supertype: Any. So extended version should use Any as argument and becomes effectively untyped. The flaw is in scala type system that supports type multiplication using with keyword, but does not support union types. You could not define Double or String.
Typed actors lose ability for easy extension. Actors shifts type checks to contravariant position and extending it requires union types. You can see how they works in ceylon programming language.
It is not that untyped and typed actors have different sphere of application. All questioned functionality may be expressed in terms of both. The choice is more about methodology and convenience.
Typing allows you to avoid some errors before going to unit testing. It will cost boilerplate for auxiliary protocol declarations. In the example above you should declare union type explicitly:
trait Protocol
final case class First(message : String) extends Protocol
final case class Second(message : Double) extends Protocol
And you lose easy callback combination: no orElse method for you. Only hand-written
val receive : PartialFunction[Protocol, Unit] = {
case First(msg) => receiveOne(msg)
case Second(msg) => receiveTwo(msg)
}
And if you would like to add a bit of new functionality with trait Three then you would be busy with rewriting that boilerplate code.
Akka provides some useful predefined enhancements for actors. They add new functionality either by mixin (e.g. receive pipeline) or by delegating (e.g. reliable proxy). Proxy patterns are used pretty much in akka applications and they change protocol on the fly, adding control command to it. That could not be done that easily with typed actors. So instead of predefined utilities you would be forced to write you own implementations. And forsaken utilities would not be limited with FSM.
It is up to you decide whether typing improvement worth increased work. No one can give precise advise without deep understanding of your project.
Typed actors are very new; they're explicitly marked as experimental and not ready for production use.
Warning
This module is currently experimental in the sense of being the subject of active research. This means that API or semantics can change without warning or deprecation period and it is not recommended to use this module in production just yet—you have been warned.
(as of the time this is written)
I'd like to point out a confusion that seems to have surfaced here.
Casper, the "typed actors" you refer to are deprecated and will be even removed eventually, I have explained in much detail why that's the case here: Akka typed actors in Java. The link you found with Viktor Klang answering, is talking about Akka 1.2 which is "ancient" as of now (when 2.4 is the stable release).
Having that said, there is a new experimental module called "Akka Typed", to which Daenyth is referring to in his reply. That module may indeed become a new core abstraction, however it's not yet ready for prime time.
I recommend you give the typed modules: Akka Streams (the latest addition to Akka, which will become not experimental very soon) and
Akka Typed to see how Actors may become typed in the near future (perhaps). Then, actually look again at Actors and see which model best works for your use case. Untyped Actors have the advantage of being a true and tried mature module / model, so you can really trust them in that sense, if you want more types - Akka Streams has you covered in many cases, but not all, so then you may consider the experimental module (but be aware, we most likely will change the Typed API while maturing it).

What is the difference between Try and Either?

According to the documentation:
The Try type represents a computation that may either result in an
exception, or return a successfully computed value. It's similar to,
but semantically different from the scala.util.Either type.
The docs do not go into further detail as to what the semantic difference is. Both seem to be able to communicate successes and failures. Why would you use one over the other?
I covered the relationship between Try, Either, and Option in this answer. The highlights from there regarding the relationship between Try and Either are summarized below:
Try[A] is isomorphic to Either[Throwable, A]. In other words you can treat a Try as an Either with a left type of Throwable, and you can treat any Either that has a left type of Throwable as a Try. It is conventional to use Left for failures and Right for successes.
Of course, you can also use Either more broadly, not only in situations with missing or exceptional values. There are other situations where Either can help express the semantics of a simple union type (where value is one of two types).
Semantically, you might use Try to indicate that the operation might fail. You might similarly use Either in such a situation, especially if your "error" type is something other than Throwable (e.g. Either[ErrorType, SuccessType]). And then you might also use Either when you are operating over a union type (e.g. Either[PossibleType1, PossibleType2]).
Since Scala 2.12, the standard library does include the conversions from Either to Try or from Try to Either. For earlier versions, it is pretty simple to enrich Try, and Either as needed:
object TryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] =
t.map(Right(_)).recover(Left(_)).get
}
}
This would allow you to do:
import TryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)
To narrowly answer your question: "What's the semantic difference":
This probably refers to flatMap and map, which are non-existent in Either and either propagate failure or map the success value in Try. This allows, for instance, chaining like
for {
a <- Try {something}
b <- Try {somethingElse(a)}
c <- Try {theOtherThing(b)}
} yield c
which does just what you'd hope - returns a Try containing either the first exception, or the result.
Try has lots of other useful methods, and of course its companion apply method, that make it very convenient for its intended use - exception handling.
If you really want to be overwhelmed, there are two other classes out there which may be of interest for this kind of application. Scalaz has a class called "\/" (formerly known as Prince), pronounced "Either", which is mostly like Either, but flatMap and map work on the Right value. Similarly, and not, Scalactic has an "Or" which is also similar to Either, but flatMap and map work on the Left value.
I don't recommend Scalaz for beginners.
Either does not imply success and failure, it is just a container for either an A or a B. It is common to use it to represent successes and failures, the convention being to put the failure on the left side, and the success on the right.
A Try can be seen as an Either with the left-side type set to Throwable. Try[A] would be equivalent to Either[Throwable, A].
Use Try to clearly identify a potential failure in the computation, the failure being represented by an exception. If you want to represent the failure with a different type (like a String, or a set of case classes extending a sealed trait for example) use Either.
Either is more general, since it simply represents disjoint unions of types.
In particular, it can represent a union of valid return values of some type X and Exception. However, it does not attempt to catch any exceptions on its own. You have to add try-catch blocks around dangerous code, and then make sure that each branch returns an appropriate subclass of Either (usually: Left for errors, Right for successful computations).
Try[X] can be thought of as Either[Exception, X], but it also catches Exceptions on its own.
Either[X, Y] usage is more general. As its name say it can represent either an object of X type or of Y.
Try[X] has only one type and it might be either a Success[X] or a Failure (which contains a Throwable).
At some point you might see Try[X] as an Either[Throwable,X]
What is nice about Try[X] is that you can chain futher operations to it, if it is really a Success they will execute, if it was a Failure they won't
val connection = Try(factory.open())
val data = connection.flatMap(conn => Try(conn.readData()))
//At some point you can do
data matches {
Success(data) => print data
Failure(throwable) => log error
}
Of course, you can always oneline this like
Try(factory.open()).flatMap(conn => Try(conn.readData()) matches {
Success(data) => print data
Failure(throwable) => log error
}
As already have been mentioned, Either is more general, so it might not only wrap error/successful result, but also can be used as an alternative to Option, for branching the code path.
For abstracting the effect of an error, only for this purpose, I identified the following differences:
Either can be used to specify a description of the error, which can be shown to the client. Try - wraps an exception with a stack trace, less descriptive, less client oriented, more for internal usage.
Either allows us to specify error type, with existing monoid for this type. As a result, it allows us to combine errors (usually via applicative effects). Try abstraction with its exception, has no monoid defined. With Try we must spent more effort to extract error and handle it.
Based on it, here is my best practices:
When I want to abstract effect of error, I always use Either as the first choice, with List/Vector/NonEmptyList as error type.
Try is used only, when you invoke code, written in OOP. Good candidates for Try are methods, that might throw an exception, or methods, that sends request to external systems (rest/soap/database requests in case the methods return a raw result, not wrapped into FP abstractions, like Future, for instance.

Custom client/server protocol in Scala

Suppose I need to implement a custom message-oriented protocol in Scala. I need to implement also the client/server code.
I would define "cases classes" for protocol messages as follows:
trait Message
case class Request1(...) extends Message
case class Response1(...) extends Message
case class Request2(...) extends Message
case class Response2(...) extends Message
... // other requests/responses
Now I need functions to read/write the messages from/to input/output streams and handle the messages.
def read(in: InputStream): Message = {...}
def write(msg: Message, out: OutputStream) {...}
def handle(msg:Message): Message = msg match {
case req: Request1 = ... // handle Request1
case resp: Response1 = ... // handle Response1
... // cases for all other message types
}
I guess it works but I wonder if I can improve the solution. How would you correct or improve it ?
Have you had a look at Akka?
Akk makes it much simpler to develop distributed applications, no need to define input and output streams manually. Just have a look at the "Remoting" example on the homepage.
The benefits of this approach would be that you can focus on the protocol itself, i.e., in your case the development of one (or more) actors on the client side, and one (or more) actors on the server side.
Akka should provide you with all 'lower-level' functionality you need, taking care of the actual sending an receiving of the messages, multi-threading, and so on; so you don't have to re-invent the wheel. This should also make your code easier to maintain by others in the future, as Akka is a well-known toolkit.
To get a basic idea of how actors work, have a look at this book chapter, but note that it describes the Scala actors, which have been replaced by Akka actors in the meantime. If you want to dig deeper, I'd recommend Akka Concurrency, which is more up to date.