Play! async action akka AskTimeoutException - scala

I am trying to make the simplest async request using an akka Actor using the ask pattern but I keep receiving the akka.pattern.AskTimeoutException no matter what. What I have is this:
object Users extends Controller {
def newUser = {
val actor = Akka.system.actorOf(Props[UserRegistration])
ActorAction[String](actor, "hello")(Ok(_))
}
}
where the ActorAction is a wrapper of the usual Async:
object ActorAction {
def apply[A](actorRef: ActorRef, msg: AnyRef, timeout: Timeout = 5 seconds)(f: A => Result)(implicit m: Manifest[A]): Action[AnyContent] = {
Action {
AsyncResult {
ask(actorRef, msg, timeout).mapTo[A].asPromise.map(f)
}
}
}
}
And the actor does nothing but logs the receiving message and returns it:
class UserRegistration extends Actor {
val log = Logging(context.system, this)
def receive = {
case u => log.info("received " + u); u
}
}
The logging of the message works just fine. I have tried everything but nothing works. Any help is more than welcome!
Play: 2.9.1
Akka: 2.0.2
Stacktrace:
[info] play - database [default] connected at jdbc:postgresql://localhost:5432/ss_dev
[info] play - Application started (Dev)
[info] play - Starting application default Akka system.
[INFO] [12/28/2012 22:10:42.51] [application-akka.actor.default-dispatcher-1] [akka://application/user/$a] received hello
[error] play - Waiting for a promise, but got an error: Timed out
akka.pattern.AskTimeoutException: Timed out
at akka.dispatch.DefaultPromise.result(Future.scala:875) [akka-actor.jar:2.0.2]
at akka.dispatch.Await$.result(Future.scala:74) ~[akka-actor.jar:2.0.2]
at play.api.libs.concurrent.AkkaPromise.await(Akka.scala:43) ~[play_2.9.1.jar:2.0.4]
at play.api.libs.concurrent.Promise$class.await(Promise.scala:55) ~[play_2.9.1.jar:2.0.4]
at play.api.libs.concurrent.AkkaPromise.await(Akka.scala:28) ~[play_2.9.1.jar:2.0.4]
at play.api.libs.concurrent.Promise$class.value(Promise.scala:53) ~[play_2.9.1.jar:2.0.4]
Caused by: akka.pattern.AskTimeoutException: Timed out
at akka.pattern.PromiseActorRef$$anonfun$1.apply$mcV$sp(AskSupport.scala:274) ~[akka-actor.jar:2.0.2]
at akka.actor.DefaultScheduler$$anon$6$$anon$7.run(Scheduler.scala:183) ~[akka-actor.jar:2.0.2]
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:94) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1381) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:259) [akka-actor.jar:2.0.2]
at akka.jsr166y.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975) [akka-actor.jar:2.0.2]
Thanks in advance!

You're not replying to the message sender ! u, please read the Akka Reference Documentation: http://doc.akka.io

Related

Akka test case assertion failure

I am trying to write test for an actor which sends:
sender() ! Status.Failure(message)
I have written the test case as:
class TestActorSpec
extends TestKit(ActorSystem("system"))
with ImplicitSender
with WordSpecLike
with Matchers {
implicit val executionContext: ExecutionContextExecutor = system.dispatcher
implicit val futureDuration: FiniteDuration = 60.seconds
val timeout: FiniteDuration = 5.seconds
val testActorRef: ActorRef = system.actorOf(Props(new TestActor()), "test-actor")
val futureResult: Future[Any] = (testActorRef ? "Exception")(timeout)
"TestSpec" should {
"send the exception in {
expectMsgType[Status.Failure]
}
}
}
But i am getting the test failure with reason:
[info] java.lang.AssertionError: assertion failed: timeout (3 seconds) during expectMsgClass waiting for class akka.actor.Status$Failure
[info] at scala.Predef$.assert(Predef.scala:223)
If you want to receive Status.Failure as a message, you should not use ask pattern ? and use tell ! instead.
The reason is that ask pattern will consume the Failure and pass back a failed Future. In case of ask pattern, you need to assert a failed Future.
From Scala docs of akka.actor.Status.Failure
This class/message type is preferably used to indicate failure of some operation performed.
As an example, it is used to signal failure with AskSupport is used (ask/?).

How to wait for Akka actor to start during tests?

I have a test that needs to make an assertion on something that happens during an actor's preStart(), but I haven't figured out how to wait until that happens, and sometimes it doesn't happen before the assertion is made (and sometimes it does). I have tried this:
EventFilter.debug(start = "started", occurrences = 1).assertDone(10.seconds)
but I get an error message when using it:
java.lang.AssertionError: assertion failed: 1 messages outstanding on DebugFilter(None,Left(started),false)
You could place the creation of the actor inside an intercept block:
import akka.actor._
import akka.testkit.EventFilter
import com.typesafe.config.ConfigFactory
class MyActor extends Actor with ActorLogging {
override def preStart(): Unit = {
log.debug("started MyActor...")
}
def receive = {
case m => log.debug(s"Received this message: $m")
}
}
object MyActor {
def props() = Props[MyActor]
}
object EventFilterTest extends App {
implicit val system = ActorSystem("testsystem", ConfigFactory.parseString("""
akka.loggers = ["akka.testkit.TestEventListener"]
akka.loglevel = "DEBUG"
"""))
EventFilter.debug(start = "started", occurrences = 1) intercept {
val myActor = system.actorOf(MyActor.props)
myActor ! "cows"
}
}
Running the above code produces the following output:
[DEBUG] [...] [run-main-0] [EventStream(akka://testsystem)] logger log1-TestEventListener started
[DEBUG] [...] [run-main-0] [EventStream(akka://testsystem)] Default Loggers started
[DEBUG] [...] [testsystem-akka.actor.default-dispatcher-5] [akka://testsystem/user/$a] Received this message: cows
The intercept "catches" the debug statement in the actor's preStart hook.

Scala Grpc failed with error io.grpc.StatusRuntimeException: CANCELLED: Failed to read message

I am trying to write a streaming service in Scala using GRPC. Towards this I wrote this proto file
syntax = "proto3";
package com.abhi.grpc;
message TimeRequest{}
message TimeResponse {
int64 currentTime = 1;
}
service Clock {
rpc StreamTime(TimeRequest) returns (stream TimeResponse);
}
This is my server side code
import com.abhi.grpc.clock.{ClockGrpc, TimeRequest, TimeResponse}
import io.grpc.stub.StreamObserver
import monix.execution.Scheduler
import monix.execution.Scheduler.{global => scheduler}
import scala.concurrent.duration._
object ClockGrpcServer extends GrpcServer with App {
val ssd = ClockGrpc.bindService(new ClockGRPC(), Scheduler.global)
runServer(ssd, "Clock")
}
class ClockGRPC extends ClockGrpc.Clock {
override def streamTime(request: TimeRequest, responseObserver: StreamObserver[TimeResponse]): Unit = {
scheduler.scheduleWithFixedDelay(0.seconds, 3.seconds) {
responseObserver.onNext(TimeResponse(System.currentTimeMillis))
}
}
}
and this is my client
object ClockGrpcClient extends App {
val channel = ManagedChannelBuilder.forAddress("localhost", 50051).usePlaintext(true).build()
val stub = ClockGrpc.stub(channel)
val observer = new StreamObserver[TimeResponse] {
override def onError(t: Throwable): Unit = println(s"failed with error ${t}")
override def onCompleted(): Unit = println("closing observer")
override def onNext(value: TimeResponse): Unit = println(s"received time ${new DateTime(value)}")
}
stub.streamTime(TimeRequest(), observer)
StdIn.readLine()
}
When I run the server and the client. The server throws the following error as soon as it receives any message from the client
io.grpc.StatusRuntimeException: CANCELLED
at io.grpc.Status.asRuntimeException(Status.java:534)
at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:279)
at com.abhi.ClockGRPC.$anonfun$streamTime$1(ClockGRPC.scala:22)
at monix.execution.internal.RunnableAction.run(RunnableAction.scala:25)
at monix.execution.schedulers.ReferenceScheduler$$anon$1.run(ReferenceScheduler.scala:45)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:140)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
I googled a little and found this article
https://blog.codecentric.de/en/2017/01/hello-grpc-scalapb/
based on this I changed my server to use the java.util scheduler
class ClockGRPC extends ClockGrpc.Clock {
val scheduler = Executors.newSingleThreadScheduledExecutor()
override def streamTime(request: TimeRequest, responseObserver: StreamObserver[TimeResponse]): Unit = {
val tick = new Runnable {
val counter = new AtomicInteger(10)
def run() =
if (counter.getAndDecrement() >= 0) {
val currentTime = System.currentTimeMillis()
responseObserver.onNext(TimeResponse(currentTime))
} else {
scheduler.shutdown()
responseObserver.onCompleted()
}
}
scheduler.scheduleAtFixedRate(tick, 0l, 3000l, TimeUnit.SECONDS)
}
}
But I still get the CANCELLED error. So i cannot get the streaming example to work.
I had almost given up on this problem. But came back today and resolved it.
The problem is with the line
override def onNext(value: TimeResponse): Unit = println(s"received time ${new DateTime(value)}")
value cannot be passed to new DateTime
To further make the matters worse. if the exception occurs in the callback method. Grpc Swallows it and replaces it with a generic error message
info] Running com.abhi.ClockGrpcClient failed with error io.grpc.StatusRuntimeException: CANCELLED: Failed to read message.
My bad luck that he DateTime uses an object as a parameter so the compilation succeeded, but the call failed at runtime and the exception was swallowed by the Grpc.
I am leaving this here so that it helps someone else.
[info] Running com.abhi.ClockGrpcClient failed with error io.grpc.StatusRuntimeException: CANCELLED: Failed to read message
Means the someone went wrong in the callback function.

TestProbe missing akka message

I'm trying to test a simple actor which is connecting to another remote on tcp. Here is my actor
/**
* Created by chris on 6/6/16.
*/
class Client(listener : ActorRef, actorSystem: ActorSystem) extends Actor with BitcoinSLogger {
/**
* The manager is an actor that handles the underlying low level I/O resources (selectors, channels)
* and instantiates workers for specific tasks, such as listening to incoming connections.
*/
def manager = IO(Tcp)(actorSystem)
def receive = {
case Tcp.Connect(remote,_,_,_,_) => manager ! Tcp.Connect(remote)
case Tcp.CommandFailed(_: Tcp.Connect) =>
logger.debug("Connection failed")
listener ! "connect failed"
context stop self
case c # Tcp.Connected(remote, local) =>
logger.debug("Tcp connection to: " + remote)
logger.debug("Local: " + local)
listener ! c
val connection = sender()
connection ! Tcp.Register(self)
context become {
case data: ByteString =>
connection ! Tcp.Write(data)
case Tcp.CommandFailed(w: Tcp.Write) =>
// O/S buffer was full
listener ! "write failed"
case Tcp.Received(data) =>
listener ! data
case "close" =>
connection ! Tcp.Close
case _: Tcp.ConnectionClosed =>
listener ! "connection closed"
context stop self
}
}
def sendMessage(msg : NetworkRequest, peer : NetworkIpAddress) : Future[NetworkResponse] = ???
}
object Client {
//private case class ClientImpl(remote: InetSocketAddress, listener: ActorRef, actorSystem : ActorSystem) extends Client
def apply(listener : ActorRef, actorSystem : ActorSystem) : Props = {
Props(classOf[Client], listener, actorSystem)
}
}
here is my test case
class ClientTest extends TestKit(ActorSystem("ClientTest")) with FlatSpecLike with MustMatchers with BeforeAndAfterAll {
"Client" must "connect to a node on the bitcoin network" in {
val probe = TestProbe()
val hostName = "testnet-seed.bitcoin.schildbach.de"
val socket = new InetSocketAddress(hostName, TestNet3.port)
val peerMessageHandler = PeerMessageHandler(system)
val client = system.actorOf(Client(peerMessageHandler, system))
probe.send(client, Tcp.Connect(socket))
probe.expectMsgType[Tcp.Connected](10.seconds)
}
override def afterAll: Unit = {
TestKit.shutdownActorSystem(system)
}
}
finally, I can tell the connection is successful because my log messages are being hit:
2016-06-08 09:58:21,548 - [DEBUG] - from class
org.bitcoins.spvnode.networking.Client in
ClientTest-akka.actor.default-dispatcher-4 Tcp connection to:
testnet-seed.bitcoin.schildbach.de:18333
2016-06-08 09:58:21,550 - [DEBUG] - from class
org.bitcoins.spvnode.networking.Client in
ClientTest-akka.actor.default-dispatcher-4 Local:
/192.168.1.107:43782
however my test case is failing with this error
[info] ClientTest:
[info] Client
[info] - must connect to a node on the bitcoin network *** FAILED ***
[info] java.lang.AssertionError: assertion failed: timeout (10 seconds) during expectMsgClass waiting for class akka.io.Tcp$Connected
[info] at scala.Predef$.assert(Predef.scala:170)
[info] at akka.testkit.TestKitBase$class.expectMsgClass_internal(TestKit.scala:435)
[info] at akka.testkit.TestKitBase$class.expectMsgType(TestKit.scala:417)
[info] at akka.testkit.TestKit.expectMsgType(TestKit.scala:737)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply$mcV$sp(ClientTest.scala:25)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply(ClientTest.scala:17)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply(ClientTest.scala:17)
[info] at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info] at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] ...
Seems like I am missing something simple, but I can't figure out exactly what it is.
To answer my own question, I just made probe the listener isntead of trying to listen on the Client actor itself.
"Client" must "connect to a node on the bitcoin network" in {
val probe = TestProbe()
val hostName = "testnet-seed.bitcoin.schildbach.de"
val socket = new InetSocketAddress(hostName, TestNet3.port)
val peerMessageHandler = PeerMessageHandler(system)
val client = TestActorRef(Client(probe.ref,system))
//probe.send(client, Tcp.Connect(socket))
client ! Tcp.Connect(socket)
probe.expectMsgType[Tcp.Connected](10.seconds)
}

AskTimeoutException: on spray-can server stop

I am trying to stop spray-can web server with the following code:
implicit val timeout = Timeout(10 seconds)
val future = ask(IO(Http)(system), Http.Unbind(10 second))
Await.result(future, Duration.Inf)
but unfortunatelly I receive the following exception:
[error] AskTimeoutException: : Timed out (AskSupport.scala:334)
[error]
akka.pattern.PromiseActorRef$$anonfun$1.apply$mcV$sp(AskSupport.scala:334)
[error] akka.actor.Scheduler$$anon$11.run(Scheduler.scala:118) [error]
akka.actor.LightArrayRevolverScheduler$TaskHolder.executeTask(Scheduler.scala:455)
[error]
akka.actor.LightArrayRevolverScheduler$$anon$12.executeBucket$1(Scheduler.scala:407)
[error]
akka.actor.LightArrayRevolverScheduler$$anon$12.nextTick(Scheduler.scala:411)
[error]
akka.actor.LightArrayRevolverScheduler$$anon$12.run(Scheduler.scala:363)
What am I doing wrong?
The problem is you are sending the Http.Unbind message to the wrong actor (i.e. the manager actor for the IO extension - in this case, Http).
You have to send the Http.Unbind message to the HttpListener (this is the actor that replies to the Http.Bind message with an Http.Bound message). The following example sends Http.Bind to the manager actor and Http.Unbind to the HttpListener:
class TestActor extends Actor {
override def preStart = {
IO(Http) ! Http.Bind(self, interface = "localhost", port = 8080)
}
def receive = {
case Http.Bound(_) =>
println("bound")
sender ! Http.Unbind(10 seconds)
case Http.Unbound =>
println("unbound")
context.stop(self)
}
}
More information can be found in the documentation section on starting and stopping.