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
Related
I am using Akka Typed (version 2.6.8) and I developed an actor that uses a message adapter.
object EncoderClient {
sealed trait Command
final case class KeepASecret(secret: String) extends Command
private final case class WrappedEncoderResponse(response: Encoded) extends Command
def apply(encoder: ActorRef[Encode]): Behavior[Command] =
Behaviors.setup { context =>
val encoderResponseMapper: ActorRef[Encoded] =
context.messageAdapter(response => WrappedEncoderResponse(response))
Behaviors.receiveMessage {
case KeepASecret(secret) =>
encoder ! Encode(secret, encoderResponseMapper)
Behaviors.same
case WrappedEncoderResponse(response) =>
context.log.info(s"I will keep a secret for you: ${response.payload}")
Behaviors.same
}
}
}
I want to test the effect of creation of the Message Adapter. I see that there is a class in the testkit library, MessageAdapter that seems to be a perfect fit to my needs.
However, I can't find anywhere an example of how to use it. Any help?
The MessageAdapter effect in the behavior testkit only signals that an adapter was created, as a result of a message or actor start. It won't help you with verifying that your adapter works.
You can inject a test probe for the encoder, expect a Encode message to get a hold of the message adapter ActorRef in the message. Something like this:
val probe = createTestProbe[Encode]()
val actor = spawn(EncoderClient(probe.ref))
actor ! KeepASecret("hush")
val encodeRequest = probe.receiveMessage()
encodeRequest ! Encoded(...)
// ... verify whatever happens on adapted response arriving...
I found a solution to my problem. If you're interested in testing if a message adapter is created by an actor for a particular type T, then you can use the BehaviorTestKit.expectEffectPF method.
It follows an example:
"EncoderClient" should "send an encoding request to the encode" in {
val encoder = TestInbox[Encode]()
val client = BehaviorTestKit(EncoderClient(encoder.ref))
client.run(KeepASecret("My secret"))
client.expectEffectPF {
case MessageAdapter(clazz, _) if clazz == classOf[Encoded] =>
}
}
If the object clazz is not of the tested type, the test fails.
Instead, if you're interested in testing that the message adapter works correctly, then, use the strategy suggested by johanandren.
#Singleton
class EventPublisher #Inject() (#Named("rabbit-mq-event-update-actor") rabbitControlActor: ActorRef)
(implicit ctx: ExecutionContext) {
def publish(event: Event): Unit = {
logger.info("Publishing Event: {}", toJsObject(event), routingKey)
rabbitControlActor ! Message.topic(shipmentStatusUpdate, routingKey = "XXX")
}
}
I want to write a unit test to verify if this publish function is called
rabbitControlActor ! Message.topic(shipmentStatusUpdate, routingKey = "XXX")
is called only once.
I am using spingo to publish messages to Rabbit MQ.
I am using Playframework 2.6.x and scala 2.12.
You can create an TestProbe actor with:
val myActorProbe = TestProbe()
and get its ref with myActorProbe.ref
After, you can verify that it receives only one message with:
myActorProbe.expectMsg("myMsg")
myActorProbe.expectNoMsg()
You probably should take a look at this page: https://doc.akka.io/docs/akka/2.5/testing.html
It depends you want to check only the message is received by that actor or you want to test the functionality of that actor.
If you want to check message got delivered to the actor you can go with TestProbe. I.e.
val probe = TestProbe()
probe.ref ! Message
Then do :
probe.expectMsg[Message]
You can make use of TestActorRef in case where you have supervisor actor, which is performing some db operations so you can over ride its receive method and stop the flow to go till DB.
I.e.
val testActor =new TestActorRef(Actor.props{
override receive :Receive ={
case m:Message => //some db operation in real flow
//in that case you can return what your actor return from the db call may be some case class.
case _ => // do something }})
Assume your method return Future of Boolean.
val testResult=(testActor ? Message).mapTo[boolean]
//Then assert your result
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.
In my Scala application say I have Actor A and Actor B. I want to devise a test case in ScalaTest that would allow me to send a message to Actor A and see what message it sends to Actor B in order to see if A is properly processing it's data and sending the right message to B. How would one test this? It took me a long time to get this cooked up on my own...but it does seem to mostly work.
class A extends Actor { ... }
class B extends Actor { ... }
class C(p: TestProbe) extends B {
override def receive = {
LoggingReceive {
case x =>
println(x.toString)
p.ref ! x
}
}
}
case class MsgToB(...)
// Spec class which extends TestKit
"A" should {
"send the right message to B" {
val p = TestProbe()
val a = TestActorRef[A]
val c = TestActorRef(Props(new C(p)))
// Assume A has a reference to C. Not shown here.
a ! msg
// Assert messages
p.expectMsgType[MsgToB]
}
}
Is this the best means of doing this? Is there a better practice?
To me it sounds like what you want is to test the behaviour of actor A in isolation. In order to do this, you need to be able to control how actor A gets its reference to actor B. For example, you could provide the reference in the actor's constructor:
import akka.actor.{Actor, ActorRef, Props}
class A(refToB: ActorRef) extends Actor { ... }
object A {
def props(refToB: ActorRef): Props = Props(new A(refToB))
}
There are alternative ways you can pass the reference to actor B to actor A, but using the constructor is arguably the easiest choice. In the example above, we also provide a method for creating the correct Props for the actor.
Now that you can control the reference to actor B, you can replace the actor reference with test probe in tests.
import akka.testkit.TestProbe
// Initialise a test probe
val probe = TestProbe()
// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))
// Send a message to actor A
a ! someMessage
// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]
Notice that I created the actor using the actor system from the TestKit instead of using the TestActorRef. This means that the actor message processing will be asynchronous instead of synchronous. Personally, I've found the asynchronous testing style to be a better fit because it better represents how the actor is run in a production system. Asynchronous testing is also recommended in the official documentation.
There is parent actor which in preStart creates child actors, one for every "active" user. Now I'd like to write a test asserting that it really happens, I mean child actors are really created for preconfigured users.
class IntegrationActor(settingsDao: UserSettingsDAO, childMaker: ActorRefFactory => UserId => ActorRef) extends Actor with StrictLogging {
val createUserActor = childMaker(context)
override def preStart(): Unit = {
val e = settingsDao.findAllEnabled()
e.map(_.userId).foreach(createUserActor)
}
// ...
}
I have test like this, but it doesn't work as all is happening off-main-test-thread
// mockMaker is already defined/mocked
it should "create child actors for users with enabled integration when started" in {
// given
val us = UserSettings(...)
Mockito.when(settingsDao.findAllEnabled()).thenReturn(Set(us))
// when
system.actorOf(Props(new IntegrationActor(settingsDao, mockMaker)))
// then
verifyMockMakerCalledFor(us)
}
I was trying to assign CallingThreadDispatcher to parent actor, but with no luck.
Theoretically I could just new this class and test it as usual, but Actor's can't be new-ed by hand.
Is there any other way to do this other than extracting stuff to trait with self type being Actor? Not sure it's the right way.