Sending a message to a TestProbe() fails sometimes with ActorInitializationException - scala

I've some sporadic test failures and struggle to figure out why. I have a bunch of actors which to the work which I want to test. At the beginning of the test I pass in an actor reference which I get from a TestProbe(). Later on the group of actors do some work and send the result to the given test probe actor reference. Then I check the result with the TestProbe():
class MyCaseSpec extends Spec with ShouldMatchers{
describe("The Thingy"){
it("should work"){
val eventListener = TestProbe()
val myStuffUnderTest = Actor.actorOf(new ComplexActor(eventListener.ref)).start();
myStuffUnderTest ! "Start"
val eventMessage = eventListener.receiveOne(10.seconds).asInstanceOf[SomeEventMessage]
eventMessage.data should be ("Result")
}
}
}
Now once in a while the test fails. And when I look through the stack trace I see that I got a 'ActorInitializationException' when sending a message to the test probe actor. However at no point in time I stop the TestProbe actor.
Here's the exception:
[akka:event-driven:dispatcher:global-11] [LocalActorRef] Actor has not been started, you need to invoke 'actor.start()' before using it
akka.actor.ActorInitializationException: Actor has not been started, you need to invoke 'actor.start()' before using it
[Gamlor-Laptop_c15fdca0-219e-11e1-9579-001b7744104e]
at akka.actor.ScalaActorRef$class.$bang(ActorRef.scala:1399)
at akka.actor.LocalActorRef.$bang(ActorRef.scala:605)
at akka.mobile.client.RemoteMessaging$RemoteMessagingSupervision$$anonfun$receive$1.apply(RemoteMessaging.scala:125)
at akka.mobile.client.RemoteMessaging$RemoteMessagingSupervision$$anonfun$receive$1.apply(RemoteMessaging.scala:121)
at akka.actor.Actor$class.apply(Actor.scala:545)
....
I'm wondering if I'm missing something obvious or am I making a subtle mistake? Or maybe something is really going wrong inside my code and I can't see it?
I'm on Akka 1.2.
Update for Vitors-Comment. At line 125 I send a message to an actor with the !-operator. Now in the test-setup thats the TestProbe actor-reference. And I can't figure out why sometimes the TestProbe actor seems to be stopped.
protected def receive = {
case msg: MaximumNumberOfRestartsWithinTimeRangeReached => {
val lastException = msg.getLastExceptionCausingRestart
faultHandling ! ConnectionError(lastException, messages.toList, self) // < Line 125. The faultHandling is the TestProbe actor
become({
// Change to failure-state behavior
}
// Snip
Anyway, I'm trying to isolate the problem further for the time being. Thanks for any hint / idea.

You are not starting your actor here. I'm not sure why your test is working some of the time. The code above needs to have the following line modified with an .start()
val myStuffUnderTest = Actor.actorOf(new ComplexActor(eventListener.ref)).start();

Ok, almost certainly found the issue =). TestProbes do have a timeout: When nothing happens after 5 seconds, they stop them self.
Now unfortunately the test takes just a little longer than 5 seconds: In that time the test-probe may stop itself all ready, which then causes the test to fail.
Fixing it is easy, increase the timeout on the TestProbe:
val errorHandler = ignoreConnectionMsgProbe()
errorHandler.setTestActorTimeout(20.seconds)

Related

Akka Sink never closes

I am uploading a single file to an SFTP server using Alpakka but once the file is uploaded and I have gotten the success response the Sink stays open, how do I drain it?
I started off with this:
val sink = Sftp.toPath(path, settings, false)
val source = Source.single(ByteString(data))
​
source
.viaMat(KillSwitches.single)(Keep.right)
.toMat(sink)(Keep.both).run()
.map(_.wasSuccessful)
But that ends up never leaving the map step.
I tried to add a killswitch, but that seems to have had no effect (neither with shutdown or abort):
val sink = Sftp.toPath(path, settings, false)
val source = Source.single(ByteString(data))
​
val (killswitch, result) = source
.viaMat(KillSwitches.single)(Keep.right)
.toMat(sink)(Keep.both).run()
result.map {
killswitch.shutdown()
_.wasSuccessful
}
Am I doing something fundamentally wrong? I just want one result.
EDIT The settings sent in to toPath:
SftpSettings(InetAddress.getByName(host))
.withCredentials(FtpCredentials.create(amexUsername, amexPassword))
.withStrictHostKeyChecking(false)
By asking you to put Await.result(result, Duration.Inf) at the end I wanted to check the theory expressed by A. Gregoris. Thus it's either
your app exits before Future completes or
(if you app does't exit) function in which you do this discards result
If your app doesn't exit you can try using result.onComplete to do necessary work.
I cannot see your whole code but it seems to me that in the snippet you posted that result value is a Future that is not completing before the end of your program execution and that is because the code in the map is not being executed either.

scala testing akka actors adding values to the db

I am trying to test run semi integration test with actors, that involve persisting to the db. the fooActor is adding kids to the db. but I have to wait till the persistence to the db will be completed using Thread.sleep :
"persist kids" in {
fooActor ! addChildToParent(bar,foo)
expectMsg("done")
fooActor ! addChildToParent(buz,foo)
expectMsg("done")
Thread.sleep(2000)
suggestionActor ! GetChildListForParent(foo)
expectMsg(
Some(List(bar,buz))
)
}
well this works fine, but I hate the fact that I have to use the Tread.sleep(2000). is there a way to minimize this effect ?
To minimize the effect, you could use awaitAssert
awaitAssert {
suggestionActor ! GetChildListForParent(foo)
expectMsg(
Some(List(bar,buz))
)
}
This awaitAssert retries the given block as long as the expected message is not received. It continues retrying until either the block does not throw an exception (in which case the test succeeds) or until the max duration expires (in which case the test fails). The max duration and interval are optional arguments of awaitAssert.

Performance issue in play application

I have a play(2.3.0) application that does some database lookups. When there are more than 6 users the application runs into performance problems.
I have narrowed down the problem to a controller with an action that does a sleep of 4 seconds.
A test client calls this action every 500 ms. I can see the the first 6 requests are processesed, and it stops a few seconds(until the 4 seconds sleep have passed) and reads the next 6.
Also: when I open 7 browser windows the 7th will not load(waits for connection).
Looking at the documentation it looks like my problem is blocking io and using the highly synchronous profile should solve my problem.
Therefore I added this profile to my application.conf but nothing changes.
my application.conf looks like this
application.context=/appname/
# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
# If you deploy your application to several instances be sure to use the same key!
application.secret="xxxxx"
play {
akka {
akka.loggers = ["akka.event.slf4j.Slf4jLogger"]
loglevel = WARNING
actor {
default-dispatcher = {
fork-join-executor {
parallelism-min = 300
parallelism-max = 300
}
}
}
}
}
and the action
def performancetestSleep() = Action{ request => {
Thread.sleep(4000)
Ok("hmmm good sleep")
}}
It seems to me the threadpool configuration is ignored. What am I missing here?
What you need for this is really just one thread which handles the 4 second delay - a scheduler. Spawning that many threads defeats the whole point of the architecture that Play has, IMHO. You could then use the scheduler to create a Future[Result] which you'd feed into an Action.async block.
Now, you don't really need to implement your own scheduler since Play depends on Akka for its concurrency; and Akka has a scheduler which will do the job.
import scala.concurrent.{Promise}
import scala.concurrent.duration._
import play.libs.Akka
val system = Akka.system()
def delayedResponse = Action.async {
import system.dispatcher
val promise = Promise[Result]
system.scheduler.scheduleOnce(4000 milliseconds) {
promise.success(Ok("Sorry for the wait!"))
}
promise.future
}
I used
activator run
to start the server, that does not seem to pick up the threadpool profile. Using
activator start
does, and now the profile seems to be used. I now need to test if this solves my problem. Will also have a look at the async call.

Control flow of messages in Akka actor

I have an actor using Akka which performs an action that takes some time to complete, because it has to download a file from the network.
def receive = {
case songId: String => {
Future {
val futureFile = downloadFile(songId)
for (file <- futureFile) {
val fileName = doSomenthingWith(file)
otherActor ! fileName
}
}
}
}
I would like to control the flow of messages to this actor. If I try to download too many files simultaneously, I have a network bottleneck. The problem is that I am using a Future inside the actor receive, so, the methods exits and the actor is ready to process a new message. If I remove the Future, I will download only one file per time.
What is the best way to limit the number of messages being processed per unit of time? Is there a better way to design this code?
There is a contrib project for Akka that provides a throttle implementation (http://letitcrash.com/post/28901663062/throttling-messages-in-akka-2). If you sit this in front of the actual download actor then you can effectively throttle the rate of messages going into that actor. It's not 100% perfect in that if the download times are taking longer than expected you could still end up with more downloads then might be desired, but it's a pretty simple implementation and we use it quite a bit to great effect.
Another option could be to use a pool of download actors and remove the future and allow the actors to perform this blocking so that they are truly handling only one message at a time. Because you are going to let them block, I would suggest giving them their own Dispatcher (ExecutionContext) so that this blocking does not negatively effect the main Akka Dispatcher. If you do this, then the pool size itself represents your max allowed number of simultaneous downloads.
Both of these solutions are pretty much "out-of-the-box" solutions that don't require much custom logic to support your use case.
Edit
I also thought it would be good to mention the Work Pulling Pattern as well. With this approach you could still use a pool and then a single work distributer in front. Each worker (download actor) could perform the download (still using a Future) and only request new work (pull) from the work distributer when that Future has fully completed meaning the download is done.
If you have an upper bound on the amount of simultanious downloads you want to happen you can 'ack' back to the actor saying that a download completed and to free up a spot to download another file:
case object AckFileRequest
class ActorExample(otherActor:ActorRef, maxFileRequests:Int = 1) extends Actor {
var fileRequests = 0
def receive = {
case songId: String if fileRequests < maxFileRequests =>
fileRequests += 1
val thisActor = self
Future {
val futureFile = downloadFile(songId)
//not sure if you're returning the downloaded file or a future here,
//but you can move this to wherever the downloaded file is and ack
thisActor ! AckFileRequest
for (file <- futureFile) {
val fileName = doSomenthingWith(file)
otherActor ! fileName
}
}
case songId: String =>
//Do some throttling here
val thisActor = self
context.system.scheduler.scheduleOnce(1 second, thisActor, songId)
case AckFileRequest => fileRequests -= 1
}
}
In this example, if there are too many file requests then we put this songId request on hold and queue it back up for processing 1 second later. You can obviously change this however you see fit, maybe you can just send the message straight back to the actor in a tight loop or do some other throttling, depends on your use case.
There is a contrib implementation of message Throttling, as described here.
The code is very simple:
// A simple actor that prints whatever it receives
class Printer extends Actor {
def receive = {
case x => println(x)
}
}
val printer = system.actorOf(Props[Printer], "printer")
// The throttler for this example, setting the rate
val throttler = system.actorOf(Props(classOf[TimerBasedThrottler], 3 msgsPer 1.second))
// Set the target
throttler ! SetTarget(Some(printer))
// These three messages will be sent to the printer immediately
throttler ! "1"
throttler ! "2"
throttler ! "3"
// These two will wait at least until 1 second has passed
throttler ! "4"
throttler ! "5"

Can I use Akka's TestEventListener without it polluting my test ouput via STDOUT?

As part of my testing, I am using EventFilter and TestEventListener to listen to log messages. However, doing so causes there to be a massive flood in my command prompt... which makes it very hard to see my tests happening.
Sample Code:
it("should send a welcome message to the user", SystemFortressTest) {
val stub = new SubFortressBuildingPermitRefTraitImplStub
EventFilter.debug(message = "SystemFortressExchange: Received Message: SystemOutput(List(JITMP Booted))", occurrences = 1) intercept {
stub.buildASubFortress(SystemFortressBlueprintRef)
}
}
this code works, but it floods me with debug level data because the TestEventListener prints to STDOUT by default (as it subclasses the default logger which is just straight STDOUT only logging)
I can roll my own logging abstraction that sits on top of Akka's and filter messages from there before it ever hits Akka's stuff... so it wouldn't pollute my command prompt... but that's an awful lot of fuss if there is a similar solution already available.
Problem is, if I use the SL4J Logger, it doesn't work with EventFilter.
What I do is:
akka.loglevel = DEBUG
akka.loggers = ["akka.event.slf4j.Slf4jLogger", "akka.testkit.TestEventListener"]
.. and then in my tests:
system.eventStream.publish(Mute(EventFilter.info()))
system.eventStream.publish(Mute(EventFilter.debug()))
This way:
errors and warnings are reported twice (but those should be fixed anyway :) )
debug and info messages are only reported through slf4j
you can still use eventfilters to check for specific messages (perhaps after unmuting them first)
Note that generally I consider testing for log messages a code smell though - usually better to check for more 'observable' behaviour. Perhaps publish an event to the eventstream.
You can configure log levels or completely turn off the logger likewise with other loggers So when you configure TestEventListener you can specify the logging as below.
akka.loggers=["akka.testkit.TestEventListener"]
akka.loglevel = OFF
Hope this helps
A solution is to create a new listener class that extends the TestEventListener and overrides the print method to either do nothing, or log through your preferred logging solution instead of printing directly to stdout. You then can specify your custom event listener as a logger in your application.conf under the akka.loggers option. (see details at https://doc.akka.io/docs/akka/2.5/scala/testing.html)
So your event listener would be:
package mypackage
import akka.testkit.TestEventListener
class SilentTestEventListener extends TestEventListener {
override def print(event: Any): Unit = ()
}
And you would add the following to application.conf:
akka {
loggers = [mypackage.SilentTestEventListener]
}
If you would turn of logging by altering the log level, or filter noisy logs by using an event filter, then you also wouldn't be able to listen to those logs in your tests, because that is also done with event filters: the logger only executes the filters on the logs until it finds the first one that filters out the log message. If it finds another such filter before the filter used in the test, then your test will never get notified about the log entry.
Another nicer solution would be to implement an event listener that defines its own way of handling logs instead of inheriting and modifying the behavior of the StdOutLogger (since you would expect a subclass of the StdOutLogger to log to stdout...), but this would require more effort than the hacky solution above, since you would have to duplicate the functionality of the TestEventListener.
When using SL4J, here is how we can setup. You will have to turn off sl4j logging to use TestEventListner for testing DEBUG logs.
class MyClassSpec extends TestKit(MyClassSpec.system) {
"MyClass" should "test something" in {
val actor = MyClassSpec.system.actorOf(Props(new MyClass()))
EventFilter.debug(message = s"Testing something", occurrences = 1) intercept {
actor ! "test"
}
}
}
object MyClassSpec {
val testConfiguation = ConfigFactory.parseString("""
akka.loglevel = DEBUG
akka.loggers = ["akka.testkit.TestEventListener"]
akka.use-slf4j=off
""")
implicit val system: ActorSystem = {
ActorSystem("MyClassSystem", testConfiguation )
}
}