I want to log all received messages to all actors in my Akka app.
There is a config akka.actor.debug.receive that will log all messages sent to an actor if that actors receive method is a LoggingReceive.
According to http://doc.akka.io/docs/akka/current/additional/faq.html it means wrapping all receive methods with LoggingReceive as in How to log all incoming messages from Akka (Java)
def receive = {
LoggingReceive {
case x ⇒ // do something
}
}
Is there a way to do this implicitly, or by config?
Not that I know of, but you should very easily be able to do something like this:
trait LoggingReceiveActor extends Actor{
def receive = LoggingReceive(loggedReceive)
def loggedReceive:Receive
}
class MyActor extends LoggingReceiveActor{
def loggedReceive = {
case _ =>
}
}
Any actor that inherits from LoggingReceiveActor now has to provide an impl for loggingReceive and if you do that, then when debug logging is enabled then this kind of actor will log the messages received.
Related
I'm testing an actor that uses an asnychronous future-based API. The actor uses the pipe pattern to send a message to itself when a future completes:
import akka.pattern.pipe
// ...
// somewhere in the actor's receive method
futureBasedApi.doSomething().pipeTo(self)
In my test I mock the API so I control future completion via promises. However, this is interleaved with other messages sent directly to the actor:
myActor ! Message("A")
promiseFromApiCall.success(Message("B"))
myActor ! Message("C")
Now I'm wondering how I can guarantee that the actor receives and
processes message B between message A and C in my test because message B is actually sent in another thread, so I can't control the order
in which the actor's mailbox receives the messages.
I thought about several possible solutions:
sleep after each message for a few milliseconds to make another
order very unlikely
wait for the actor to acknowledge each message, although
acknowledgement is only required for testing
send message B directly to the actor to simulate completion of the
future and write a separate test that ensures that the pipe pattern
is properly used (the test above would not fail if the actor would
not pipe the result message to itself)
I don't really like either of these options but I tend to use the last
one. Is there another better way I can enforce a certain message order in the tests?
Clarification: The question is not how to deal with the fact that messages might be received in random order in production. Controlling the order in the test is essential to make sure that the actor can actually deal with different message orders.
One idea is to define a flag in your actor that indicates whether the actor has received message B. When the actor receives message C, the actor can stash that message C if the flag is false, then unstash it once the actor receives message B. For example:
class MyActor extends Actor with Stash {
def receiveBlock(seenMsgB: Boolean, seenMsgC: Boolean): Receive = {
case MakeApiCall =>
callExternalApi().mapTo[MessageB].pipeTo(self)
case m: MessageB if seenMsgC => // assume msg C has been stashed
unstashAll()
// ...do something with msg B
become(receiveBlock(true, seenMsgC)) // true, true
case m: MessageB if !seenMsgC =>
// ...do something with message B
become(receiveBlock(true, seenMsgC)) // true, false
case m: MessageC if seenMsgB =>
// ...do something with message C
context.become(receiveBlock(seenMsgB, true)) // true, true
case m: MessageC if !seenMsgB =>
stash()
context.become(receiveBlock(seenMsgB, true)) // false, true
case ...
}
def receive = receiveBlock(false, false)
}
After reading a lot more about akka, I finally found a better solution: Replacing the actor mailbox with one I can observe in the tests. This way I can wait until the actor receives a new message after I complete the promise. Only then the next message is sent. The code for this TestingMailbox is given at the end of the post.
Update: In Akka Typed this can be achieved very elegantly with a BehaviorInterceptor. Just wrap the Behavior under test with a custom interceptor that forwards all messages and signals but lets you observe them.
The mailbox solution for untyped Akka is given below.
The actor can be configured like this:
actorUnderTest = system.actorOf(Props[MyActor]).withMailbox("testing-mailbox"))
I have to make sure the "testing-mailbox" is known by the actor system by providing a configuration:
class MyTest extends TestKit(ActorSystem("some name",
ConfigFactory.parseString("""{
testing-mailbox = {
mailbox-type = "my.package.TestingMailbox"
}
}""")))
with BeforeAndAfterAll // ... and so on
With this being set up, I can change my test like this:
myActor ! Message("A")
val nextMessage = TestingMailbox.nextMessage(actorUnderTest)
promiseFromApiCall.success(Message("B"))
Await.ready(nextMessage, 3.seconds)
myActor ! Message("C")
With a little helper method, I can even write it like this:
myActor ! Message("A")
receiveMessageAfter { promiseFromApiCall.success(Message("B")) }
myActor ! Message("C")
And this is my custom mailbox:
import akka.actor.{ActorRef, ActorSystem}
import akka.dispatch._
import com.typesafe.config.Config
import scala.concurrent.{Future, Promise}
object TestingMailbox {
val promisesByReceiver =
scala.collection.concurrent.TrieMap[ActorRef, Promise[Any]]()
class MessageQueue extends UnboundedMailbox.MessageQueue {
override def enqueue(receiver: ActorRef, handle: Envelope): Unit = {
super.enqueue(receiver, handle)
promisesByReceiver.remove(receiver).foreach(_.success(handle.message))
}
}
def nextMessage(receiver: ActorRef): Future[Any] =
promisesByReceiver.getOrElseUpdate(receiver, Promise[Any]).future
}
class TestingMailbox extends MailboxType
with ProducesMessageQueue[TestingMailbox.MessageQueue] {
import TestingMailbox._
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef],
system: Option[ActorSystem]) =
new MessageQueue()
}
If it is so important to order messages you should use ask (?) which returns Future and chain them even if you dont expect any response from an actor.
The Akka documentation says that the mailbox is NOT scanned for messages. Each message is handled after another (FIFO by default) in the order of their arrival. However, when I send a message from an actor to another which is not matched be the receiving actor, it is neither moved to the deadletters actor (which would appear in the log I suppose) nor does it block handling the next message in the mailbox which arrives one second later and can be handled correctly.
What does happen to the unmatched message from the mailbox?
I am using Scala 2.10.4 and Akka 2.4-SNAPSHOT in sbt.
package main.scala
import akka.actor._
class SRActor(dest: ActorRef) extends Actor with ActorLogging {
dest ! A
dest ! B
context.stop(self)
override def receive = {
case _ => {
log.info("Finally got something")
}
}
}
class SRActorReceiver extends Actor with ActorLogging {
override def receive = {
case B =>
log.info("Finally got B")
}
}
Actor creation:
package main.scala
import akka.actor._
case object A
case object B
object ErrorApp extends App {
// SR: Send nowhere received
var system6 = ActorSystem("ErrorActorSystem")
val srActorReceiver = system6.actorOf(Props(classOf[SRActorReceiver]), "sractorreceiver")
val sractor = system6.actorOf(Props(classOf[SRActor], srActorReceiver), "sractor")
// wait until actors have finished
Thread.sleep(1000)
system6.shutdown
Copied from docs
Please note that the Akka Actor receive message loop is exhaustive,
which is different compared to Erlang and the late Scala Actors. This
means that you need to provide a pattern match for all messages that
it can accept and if you want to be able to handle unknown messages
then you need to have a default case as in the example above.
Otherwise an akka.actor.UnhandledMessage(message, sender, recipient)
will be published to the ActorSystem's EventStream.
There is also unhandled method in Actor trait that you can override. (docs)
def unhandled(message: Any): Unit
User overridable callback.
Is called when a message isn't handled by the current behavior of the actor by default it fails with either a akka.actor.DeathPactException (in case of an unhandled akka.actor.Terminated message) or publishes an akka.actor.UnhandledMessage to the actor's system's akka.event.EventStream
I'm working with Play! Scala 2.4 and I have a Websocket handled by an actor as following:
object MyWebSocketActor {
def props(out: ActorRef) = Props(classOf[MyWebSocketActor], out)
}
class MyWebSocketActor #Inject()(out: ActorRef) extends Actor {
override def receive = {
case msg: String => out ! ("I received your message: " + msg)
case _ => out ! "I did not received your message: "
}
}
class MessagesController extends Controller {
def openSocket = WebSocket.acceptWithActor[String, String] { request => out =>
MyWebSocketActor.props(out)
}
}
It works well but I would like to send to it (MyWebSocketActor) some messages from an other actor and I don't manage to make it.
I tried to start it when my application starts with AkkaGuiceSupport like this: bindActor[MyWebSocketActor]("MyWebSocketActor") in order to be able to inject it in an other actor like this: (#Named("MyWebSocketActor") myWebSocketActor: ActorRef) but I get an error since I did not provide an ActorRef when I bind the actor.
The Guice error is:
No implementation for akka.actor.ActorRef was bound.
while locating akka.actor.ActorRef
for parameter 0 at controllers.MyWebSocketActor
How can I do that?
The "instance" of MyWebSocketActor is created per connection. So when you want to send a message to it, I guess you want to send message to all instances of MyWebSocketActor (which will transfer those messages to all browsers which have a connection to the websocket)
In that case, you can use the "PubSub" module, have MyWebSocketActor subscribe to a topic, and publish message from your other actors to that.
Here's a activator template which has very good sample regarding this: http://www.lightbend.com/activator/template/akka-clustering?_ga=1.54579683.939088969.1455862030
Here's the document for PubSub module http://doc.akka.io/docs/akka/2.4.2/scala/distributed-pub-sub.html
Now, I am asked to add logging function in akka's actor.
When a message is received, before it is handled, this message should be written into log.
And before a message is sent out, this message should be logged first.
I think I should override the receive and send functions in Actor. Suppose I create a trait actorlog which extends Actor. And class myActor extends actorlog. But in myActor, I need to override receive function (it seems it causes problems here). So I am confused what I should do.
PS. I know akka provides logging. But now I need implement this function by myself.
There is a utility to get logging of the received messages in Akka. It's briefly mentioned in the logging documentation. Basically you wrap your receive function in it like this:
def receive = LoggingReceive {
// your normal receive here
}
And then you enable it in your config with:
akka.actor.debug.receive=on
The information will be logged at debug level.
Besides the other answers here, another approach is to use orElse to prepend a partial function to your receive. In that partial function, put the logging in isDefinedAt so it gets called on every message.
For example:
trait ReceiveLogger {
this: Actor with ActorLogging =>
def logMessage: Receive = new Receive {
def isDefinedAt(x: Any) = {
log.debug(s"Got a $x")
false
}
def apply(x: Any) = throw new UnsupportedOperationException
}
}
class MyActor extends Actor with ActorLogging with ReceiveLogger {
def receive: Receive = logMessage orElse {
case ...
}
}
Using orElse is a general approach for composing receive behavior. In most cases I am composing things like this:
def otherBehavior: Receive = {
case OtherMessage => ...
}
class MyActor extends Actor {
def receive = otherBehavior orElse {
case ...
}
}
A good example of the stackable traits approach can be seen in this presentation: http://www.slideshare.net/EvanChan2/akka-inproductionpnw-scala2013
use stackable modificator abstract override for stackable call of receive method.
use new feature of Akka: event-sourced actor system (docs here).
Is it possible to send a message to all actors in an actor system? I've been looking at the Broadcast router example, but that is so marginal I can't comprehend how I add actors to the router dynamically.
We are using scala for akka.
Thanks!
system.actorSelection("/user/*") ! msg
Selects all children of the guardian and sends them the msg.
If you want send a message to all actor who are dynamically created, you can use eventBus
I personally use the system.eventStream for my case.
From an actor, you can send to everyone :
context.system.eventStream.publish(StatisticsMessage())
or directly with system.
actor must subscribe with :
context.system.eventStream.subscribe
I extends from :
trait SubscriberActor extends Actor {
def subscribedClasses: Seq[Class[_]]
override def preStart() {
super.preStart()
subscribedClasses.foreach(this.context.system.eventStream.subscribe(this.self, _))
}
override def postStop() {
subscribedClasses.foreach(this.context.system.eventStream.unsubscribe(this.self, _))
super.postStop()
}
}