Akka cluster singleton as scheduler - scala

I am running Play with an Akka cluster.
I need an "Singleton Scheduler" to execute some tasks every hour.
What I found out so far is, that I should use ClusterSinglegonManager.
But I am not sure how my Actor must look like.
In my opinion, I wouldn't need a "receive" Method.
That is, how I instatiate my Singleton:
system.actorOf(
ClusterSingletonManager.props(
singletonProps = MySingletonActor.props(configuration),
terminationMessage = PoisonPill,
settings = ClusterSingletonManagerSettings(system)),
name = "mysingletonactor")
That would fit:
object MySingletonActor {
def props(configuration: Configuration): Props = Props(new MySingletonActor(configuration))
}
class MySingletonActor(configuration: Configuration) extends Actor with ActorLogging {
context.system.scheduler.schedule(2 seconds, 2 seconds)(println("Hallo Welt"))
def receive = ???
}
But of course it raises exceptions, because of the missing implementation of the receive method. But it works.
What is the best way to go here?
It feels awkward to just schedule a "Tick" and handle the Tick in the receive Method...
class MySingletonActor(configuration: Configuration) extends Actor with ActorLogging {
case object Tick
context.system.scheduler.schedule(2 seconds, 2 seconds, self, Tick)
def receive = { case Tick => println("Hallo Welt") }
}
Is there any kind of a Singleton Scheduler in Akka?

Instead of writing ??? as receive method, you can use Actor.emptyBehavior to not raise an Exception. This is a Receive-expression that matches no messages at all, ever.

Related

Akka: issue with Timer

I'm trying to create actor, which perform some action on timer. So I seek a way to schedule actor messages to self.
For this aim I use Behaviors.withTimers
object Consumer {
sealed trait Command
private object Timeout extends Command
private case object TimerKey
def apply(): Behavior[Command] = {
Behaviors.withTimers(timers => new Consumer(timers).idle())
}
}
Method idle() must start sending messages Timeout to self in regular intervals.
class Consumer(timers: TimerScheduler[Command]) {
private def idle(): Behavior[Command] = {
timers.startTimerWithFixedDelay(TimerKey, Timeout, FiniteDuration.apply(1, SECONDS))
action()
Behaviors.same
}
def action(): Behavior[Command] = {
Behaviors.receiveMessage[Command] {
case Timeout => println(" Consumer action done")
Behaviors.same
}
}
}
And action() must hook this messages against Behavior[Command]. But this is not happening. For some reasons, as I understand, timers not started. But what are that reasons?
The timers are being started and the Timeout message is being sent, but your Consumer actor isn't handling it, so the println never executes.
Your apply injects timers into Consumer. In idle, you're starting the timer, then calling action to construct a new Behavior, but you then throw it away and actually use the same behavior your actor has (which won't respond to any messages).
idle should probably be defined along these lines (I'm also using the duration DSL: import scala.concurrent.duration._)
timers.startTimerWithFixedDelay(TimerKey, Timeout, 1.second)
action()

ExecutionContext causes Akka dead letter

For some reason I have to use gRPC and Akka at the same time. When this actor is started as a top actor, nothing goes wrong (in this little demo). But when it becomes a child actor, it cannot receive any messages, and the following is logged:
[default-akka.actor.default-dispatcher-6] [akka://default/user/Grpc] Message [AkkaMessage.package$GlobalStart] from Actor[akka://default/user/TrackerCore#-808631363] to Actor[akka://default/user/Grpc#-1834173068] was not delivered. [1] dead letters encountered.
The example core:
class GrpcActor() extends Actor {
val ec = scala.concurrent.ExecutionContext.global
val service = grpcService.bindService(new GrpcServerImpl(), ec)
override def receive: Receive = {
case GlobalStart() => {
println("GlobalStart")
}
...
}
}
I tried to create a new ExecutionContext like:
scala.concurrent.ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))
Why is this happening, and how do can I debug a dead letters problem like this (no exception is thrown)?
Update:
Sorry I didn't list everything here. I used normal Main method to test GrpcActor as top actor, and ScalaTest to test it as child actor, which is a mistake.
class GrpcActorTest extends FlatSpec with Matchers{
implicit val system = ActorSystem()
val actor: ActorRef = system.actorOf(Props[GrpcActor])
actor ! GlobalStart()
}
It is this empty test suite that active shutdown the whole actor system. But the problem is with this line
val service = grpcService.bindService(new GrpcServerImpl(), ec)
the delivery of GlobalStart() was delayed after the shutdown.
Without that line, message can be delivered before the shutdown.
Is this a normal behavior?
(My guess: it happened that the GlobalStart() was queued after the shutdown message with that line, which did some heavy work and made the difference in time)
One way to address the problem is to make service a lazy val:
class GrpcActor extends Actor {
...
lazy val service = grpcService.bindService(new GrpcServerImpl(), ec)
...
}
A lazy val is useful for long-running operations: in this case, it defers the initialization of service until it is used for the first time. Without the lazy modifier, service is initialized when the actor is created.
An alternative approach is to add a Thread.sleep in your test to prevent the actor system from shutting down before the actor has fully initialized:
class GrpcActorTest extends FlatSpec with Matchers {
...
actor ! GlobalStart()
Thread.sleep(5000) // or whatever length of time is needed to initialize the actor
}
(As a side note, consider using the Akka Testkit for your actor tests.)
Add a supervisor strategy to its parent, add println to the actor lifecycle. There is something that kill your actor . Finally, if you provide a complete example maybe I can say more :)

Why creating an actor within actor is dangerous

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.

Scala and Akka - Testing actors as a system with Akka Testkit

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.

Testing timer events in akka

I have a function which uses scheduleOnce to schedule an event to happen some time in the future, and I want to write a test that checks that:
the event was indeed scheduled
it was scheduled at the correct time
the system behaves as expected when that event eventually triggers
but I don't want the test to actually wait several minutes doing nothing.
How should I best test code that uses akka's Scheduler?
Here is an example of mocking out the scheduler as described by #lmm. In this example, we really test the full scheduling and handling of the action as two separate scenarios. The first testing that given some condition (a message of a certain type being received in my example) we will schedule a callback, and the second being the handling of the message that gets fired back to self when that timer goes off. The code is as follows:
object TimerExampleActor{
case object ClearState
case class ScheduleStateClearing(duration:FiniteDuration)
}
class TimerExampleActor extends Actor{
import TimerExampleActor._
var state:List[Int] = Nil
def receive = {
case ScheduleStateClearing(d) =>
scheduler.scheduleOnce(d, self, ClearState)(context.dispatcher)
case ClearState =>
state = Nil
}
def scheduler = context.system.scheduler
}
Then, using specs2 and mockito, my test case is as follows:
class TimerExampleActorTest extends Specification with Mockito with NoTimeConversions{
import TimerExampleActor._
implicit val system = ActorSystem("test")
trait testscope extends Scope{
val mockScheduler = mock[Scheduler]
val actor = TestActorRef(new TimerExampleActor{
override def scheduler = mockScheduler
})
}
"A request to schedule state clearing" should{
"schedule a callback for the message ClearState to self with the supplied duration" in new testscope{
val dur = 1.minute
actor ! ScheduleStateClearing(dur)
there was one(mockScheduler).scheduleOnce(dur, actor, ClearState)(actor.underlyingActor.context.dispatcher)
}
}
"A ClearState message received by the actor" should{
"clear the interval 'state' List" in new testscope{
actor.underlyingActor.state = List(1,2,3)
actor ! ClearState
actor.underlyingActor.state mustEqual Nil
}
}
}
You can see that when I create the actor instance under test I override the method I created to get me the instance of the scheduler, allowing me to return a mock. This is not the only way to go about testing something like this, but it certainly can be one option for you to consider.
Make the scheduler take a time parameter. In your test use a shorter time than in your regular code.
Or... when testing you can mix in a special trait that modifies your class as needed (shortens the wait time.)