Akka (JVM): Serialize an actorref with protobuf within another message - scala

I have the following scala object that I would like to serialize with protobuf:
case class Worker(id: String, ref: ActorRef)
My understanding is that Akka comes with a ProtobufSerializer that I can use to serialize from/to ActorRef. Therefore I defined the following message in a proto file:
message Worker {
string id = 1;
bytes ref = 2;
}
However the static methods ProtobufSerializer take an ExtentendActorSystem that I do not have at hand when I need to serialize those messages (only an ActorSystem through the context.system attribute of my actor). I am not sure how to actually serialize my object to protobuf and the other way around.

I am not sure in which cases it is true, but I was able to simply cast my ActorSystem to an ExtendedActorSystem. In my specific case (I am using Akka Persistence with Akka Singleton) it seems to work fine.

Related

InvalidDefinitionException: Cannot construct instance of `org.slf4j.Logger`

I have a akka cluster of microservices running on nodes. I'm trying to use the Jackson serializer for application specific messages exchanged between the nodes (microservices).
My code is written in scala, not Java
I'm using scala 'case class' as akka messages exchanged between actors and each message (case class) have a val LOG:org.slf4j.Logger built in to log specific business logic processing information.
When I send messages between nodes I'm getting the exception
WARN akka.remote.artery.Deserializer - Failed to deserialize message from [akka://MyCluster#127.0.0.1:25251] with serializer id [33] and manifest [com...MyCaseClassMessage]. com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.slf4j.Logger (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: ..."[truncated 'n' bytes]; line: 'n', column: 'n'] (through reference chain: com...MyCaseClassMessage["LOG"])
My case class essentially is something like:
case class MyCaseClassMessage()
extends CborSerializable {
override val LOG:Logger = LoggerFactory.getLogger(classOf[MyCaseClassMessage])
val businessLogic:Array[Byte] = ...
def apply():Array[Byte] = ...
}
I have no idea of how to specify to Jackson how to serialize and (or) deserialize a "val LOG:Logger" in my case class. I just know that if I remove my Logger, substituing it to (for example) println("message") I don't have any problem with serialization and deserialization.
Any help?
Because Jackson relies on reflection and does not understand the convention in Scala case classes that only the constructor parameters are required for defining the message, it will attempt to serialize every field of the object.
The LOG field can be ignored by Jackson by annotating it with an #JsonIgnore annotation (com.fasterxml.jackson.annotation.JsonIgnore):
#JsonIgnore
override val LOG: Logger = LoggerFactory.getLogger(classOf[MyCaseClassMessage])

Unit Testing Components that Uses an Akka Actor

First of all, I am not asking how to unit test an Akka Actor. I know the techniques to do that. My problem is slightly different.
I am developing a Scala program, let's call it the client, that does not use Akka Actors. However, the program uses a library, let's call it the server, whose interface is implemented using an Akka Actor.
Then, through the ask pattern, the client interacts with the server.
// This is the client program
class Client(uri: String) {
implicit val context: ActorSystem = ActorSystem("client-actor-system")
private val mainActor = context.actorSelection(uri)
def connect: Future[SomeClass] = {
implicit val timeout: Timeout = Timeout(5 seconds)
(mainActor ? Connect()).mapTo[CreationResponse]
}
}
Now, I want to write down some unit tests for Client class. Unit testing means to test a class in isolation. Every external dependency should be mocked.
How can I mock the reference to mainActor inside Client class? How can I inject in the actor system a mock actor for mainActor?
Thanks in advance.
I would inject the mainActor actor selection into the client, and create that using Akka TestKits.
Of course, you need an ActorSelection, not an ActorRef. Some solutions for that can be found here:
Giving an ActorPath for a testProbe
Or alternatively, you could make mainActor an ActorRef by sending an Identify message to the ActorSelection.

(Scala) Recognize the type a serialized object by Kryo which is sent through network using UDP

Currently I am having a problem of recognizing a receiving serialized object which is sent through network using UDP.
I have an abstract class called MsgType:
sealed abstract class MsgType
case class Msg(message : String) extends MsgType
case class End() extends MsgType
in that, Msg means a normal message whilst End means a termination request at client side.
===========================================================================
At server side, I have a function call isMessage to detect whether it's a normal message or the termination request:
def isMessage(message: AnyRef): Boolean = {
message match{
case End => false
case Msg(message) => true
}
}
===========================================================================
Here is the code using Kryo for receiving the message sent from client:
val inputString = kyro.readObject(input, classOf[MsgType])
println("incoming Message: " + isMessage(inputString))
However, when I run the code, there is an exception named:
Exception in thread "main" com.esotericsoftware.kryo.KryoException: Error
constructing instance of class: MsgType
I know it's because MsgType is an abstract class....
Could anyone suggest me a better solution to deal with this problem of recognizing the type of received serialized object?
Thanks and Best Regards,
Long.
Unfortunately Kryo doesn't work this way. It should know the type of object being deserialized before deserialization is started. It means you need to save this information in your serialized data as well. Conviently Kryo provides writeClassAndObject and readClassAndObject that do exactly that.
Also I expect that you'll have another issue related to the usage of the case classes. Unless you provided custom deserializators, Kryo will fail because your Msg case class doesn't have a default constructor (i.e. one with no parameters). You may consider using twitter chill - a Scala wrapper for Kryo. See alao Handling case classes in twitter chill (Scala interface to Kryo)?

Declaring Actor state variables as mutable ones

I am fairly new with Akka framework and Concurrency concepts. And from Akka docs, I understood that only one message in the Actor mailbox would be processed at a time. So single thread would be processing Actor's state at a time. And my doubt is that, so declaring an Actor state/data variable as mutable - 'Var'(Only when 'Val' doesn't fit), will not cause inconsistent Actor states in the case of Concurrency.
I am using Scala for development. In the following Master actor, details of workers is stored in a mutable variable 'workers'. Will it be a problem with concurrency?
class Master extends PersistentActor with ActorLogging {
...
private var workers = Map[String, WorkerState]()
...
}
I think what you are doing is fine. As you said, one of the fundamental guarantees of Akka actors is that a single actor will be handling one message at a time, so there will not be inconsistent Actor states.
Akka actors conceptually each have their own light-weight thread,
which is completely shielded from the rest of the system. This means
that instead of having to synchronize access using locks you can just
write your actor code without worrying about concurrency at all.
http://doc.akka.io/docs/akka/snapshot/general/actors.html
Also, it is a good thing that you're using a var instead of a val with a mutable map :)
Another way to consider coding situations like these is to alter the actor's "state" after each message handled. Eg.:
class Master extends PersistentActor with ActorLogging {
type MyStateType = ... // eg. Map[String, WorkerState], or an immutable case class - of course, feel free to just inline the type...
def receive = handle(initState) // eg. just inline a call to Map.empty
def handle(state: MyStateType): Actor.Receive = LoggingReceive {
case MyMessageType(data) =>
... // processing data - build new state
become(handle(newState))
case ... // any other message types to be handled, etc.
}
... // rest of class implementation
}
While it is true that there is still mutable state happening here (in this case, it is the state of the actor as a whole - it becomes effectively a "non-finite state machine"), it feels better contained/hidden (to me, at least), and the "state" (or "workers") available to the actor for any given message is treated as entirely immutable.

Getting instance of class used to create an actor in Akka in test

How do I get instance of class I passed to Props when creating an actor with ActorSystem.actorOf? I need that for unit tests to get reference to some properties of the actor, so the actor is local in the same JVM as test.
I don't want to use Akka's test framework because I need the actor live, it's kind of integration tests.
The underlying instance of an Actor subclass is well and truly sealed off from you and you're not going to get at it without mucking with Akka code itself. If you look at the definition of the ActorRef you'll see that it doesn't even contain a reference to the Actor!
Similarly, you cannot instantiate Actor subclasses directly using new.
I guess the Akka designers were serious about the ActorRef / Actor firewall...
The Akka Testkit is made for integration testing. To get access to the internal state of an actor send it a message asking for it. Your actor can reply to the sender which is the TestKit's testActor.