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.
Related
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/?).
Good morning , I hava a problem with basic akka IO by TCP
I've a basic implemetation of Client and Server as shown on akka documentation:
Client is https://github.com/akka/akka/blob/v2.5.20/akka-docs/src/test/scala/docs/io/IODocSpec.scala#L67-L103
And Handler is [SimpleEchoHandler] (https://github.com/akka/akka/blob/v2.5.20/akka-docs/src/test/scala/docs/io/EchoServer.scala#L227-L304) but also the other act as the same way.
I've a main test method that stop on first connection to the server:
package core.september
import java.net.InetSocketAddress
import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props}
import akka.util.ByteString
import com.typesafe.config.ConfigFactory
import core.september.fastchain.network.Client
/**
* #author ${user.name}
*/
object App {
class ClientHandler extends Actor with ActorLogging {
def receive = {
case toLog ⇒ {
log.debug("Client received "+ toLog.toString)
}
//Thread.sleep(200)
}
}
def main(args : Array[String]) {
val config = ConfigFactory.parseString("akka.loglevel = DEBUG")
implicit val system = ActorSystem("EchoServer", config)
var clientHand:ActorRef = system.actorOf(Props(classOf[ClientHandler]))
var address:InetSocketAddress = new InetSocketAddress("localhost",5080)
var ackServer = system.actorOf(Props(classOf[EchoManager], classOf[SimpleEchoHandler],5080), "simple")
var client:ActorRef = system.actorOf(Props(classOf[Client],address,clientHand));
//Thread.sleep(200)
client ! ByteString("echo")
//Thread.sleep(200)
client ! "close"
}
}
If I' don't comment out the two Thread.sleep after each message I can't see the output of the sent message, the output, without sleep is just:
[DEBUG] [02/07/2019 15:47:21.812] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Attempting connection to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:47:21.816] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Connection established to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:47:21.825] [EchoServer-akka.actor.default-dispatcher-3] [akka://EchoServer/user/$a] Client received Connected(localhost/127.0.0.1:5080,/127.0.0.1:54616)
I completely loose ByteString message and the "close" message.
My question is why i need to put the main thread in sleep to show also other messages.
With thread.sleep message are correctly logged:
[DEBUG] [02/07/2019 15:53:55.988] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Attempting connection to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:53:55.999] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Connection established to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:53:56.011] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/user/$a] Client received Connected(localhost/127.0.0.1:5080,/127.0.0.1:54712)
[DEBUG] [02/07/2019 15:53:56.157] [EchoServer-akka.actor.default-dispatcher-2] [akka://EchoServer/user/$a] Client received ByteString(101, 99, 104, 111)
[DEBUG] [02/07/2019 15:53:56.374] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/user/$a] Client received connection closed
ClientActor implementation is:
package core.september.fastchain.network
import akka.actor.{ Actor, ActorRef, Props }
import akka.io.{ IO, Tcp }
import akka.util.ByteString
import java.net.InetSocketAddress
object Client {
def props(remote: InetSocketAddress, replies: ActorRef) =
Props(classOf[Client], remote, replies)
}
class Client(remote: InetSocketAddress, listener: ActorRef) extends Actor {
import Tcp._
import context.system
import akka.io.Tcp
/*if (listener == null) {
listener = Tcp.get(context.system).manager
}*/
IO(Tcp) ! Connect(remote)
def receive = {
case CommandFailed(_: Connect) ⇒
listener ! "connect failed"
context stop self
case c # Connected(remote, local) ⇒
listener ! c
val connection = sender()
connection ! Register(self)
context become {
case data: ByteString ⇒
connection ! Write(data)
case CommandFailed(w: Write) ⇒
// O/S buffer was full
listener ! "write failed"
case Received(data) ⇒
listener ! data
case "close" ⇒
connection ! Close
case _: ConnectionClosed ⇒
listener ! "connection closed"
context stop self
}
}
}
thank you vey much.
You gotta wait for the actor to process your messages before exiting the app.
The easiest way is to use Akka's gracefulStop pattern:
import akka.pattern.gracefulStop
client ! ByteString("echo")
client ! "close"
Await.result(gracefulStop(client, 1 second)(system)
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.
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)
}
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