diff --git a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala
index 15bf70b2e6..4fbb67fbb4 100644
--- a/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala
+++ b/akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala
@@ -64,9 +64,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val future = Promise[String]().complete(Left(new RuntimeException(message)))
behave like futureWithException[RuntimeException](_(future, message))
}
- "completed with a j.u.c.TimeoutException" must {
- val message = "Boxed TimeoutException"
- val future = Promise[String]().complete(Left(new TimeoutException(message)))
+ "completed with an InterruptedException" must {
+ val message = "Boxed InterruptedException"
+ val future = Promise[String]().complete(Left(new InterruptedException(message)))
behave like futureWithException[RuntimeException](_(future, message))
}
"completed with a NonLocalReturnControl" must {
diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala
index c9da4d5ae7..ee53fec688 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala
@@ -13,7 +13,7 @@ import java.util.concurrent.TimeUnit
import akka.event.EventStream
import akka.event.DeathWatch
import scala.annotation.tailrec
-import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.{ ConcurrentHashMap, TimeoutException }
import akka.event.LoggingAdapter
import java.util.concurrent.atomic.AtomicBoolean
@@ -106,6 +106,8 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable
* Akka Java API.
*
* Sends a message asynchronously returns a future holding the eventual reply message.
+ * The Future will be completed with an [[akka.actor.AskTimeoutException]] after the given
+ * timeout has expired.
*
* NOTE:
* Use this method with care. In most cases it is better to use 'tell' together with the sender
@@ -177,6 +179,9 @@ trait ScalaActorRef { ref: ActorRef ⇒
/**
* Sends a message asynchronously, returning a future which may eventually hold the reply.
+ * The Future will be completed with an [[akka.actor.AskTimeoutException]] after the given
+ * timeout has expired.
+ *
* NOTE:
* Use this method with care. In most cases it is better to use '!' together with implicit or explicit
* sender parameter to implement non-blocking request/response message exchanges.
@@ -489,6 +494,14 @@ class VirtualPathContainer(val path: ActorPath, override val getParent: Internal
}
}
+/**
+ * This is what is used to complete a Future that is returned from an ask/? call,
+ * when it times out.
+ */
+class AskTimeoutException(message: String, cause: Throwable) extends TimeoutException {
+ def this(message: String) = this(message, null: Throwable)
+}
+
class AskActorRef(
val path: ActorPath,
override val getParent: InternalActorRef,
diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala
index 115fca87d5..57ef9f108c 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala
@@ -6,14 +6,12 @@ package akka.actor
import java.util.concurrent.atomic.AtomicLong
import org.jboss.netty.akka.util.{ TimerTask, HashedWheelTimer }
-import akka.util.Timeout
import akka.util.Timeout.intToTimeout
import akka.config.ConfigurationException
import akka.dispatch._
import akka.routing._
-import akka.util.Timeout
import akka.AkkaException
-import akka.util.{ Duration, Switch, Helpers }
+import akka.util.{ Duration, Switch, Helpers, Timeout }
import akka.event._
import java.io.Closeable
@@ -485,15 +483,15 @@ class LocalActorRefProvider(
def ask(within: Timeout): Option[AskActorRef] = {
(if (within == null) settings.ActorTimeout else within) match {
- case t if t.duration.length <= 0 ⇒
- None
+ case t if t.duration.length <= 0 ⇒ None
case t ⇒
val path = tempPath()
val name = path.name
val a = new AskActorRef(path, tempContainer, dispatcher, deathWatch)
tempContainer.addChild(name, a)
- val f = dispatcher.prerequisites.scheduler.scheduleOnce(t.duration) { tempContainer.removeChild(name); a.stop() }
- a.result onComplete { _ ⇒
+ val result = a.result
+ val f = dispatcher.prerequisites.scheduler.scheduleOnce(t.duration) { result.failure(new AskTimeoutException("Timed out")) }
+ result onComplete { _ ⇒
try { a.stop(); f.cancel() }
finally { tempContainer.removeChild(name) }
}
diff --git a/akka-actor/src/main/scala/akka/dispatch/Future.scala b/akka-actor/src/main/scala/akka/dispatch/Future.scala
index 2ce0721f25..59996e9311 100644
--- a/akka-actor/src/main/scala/akka/dispatch/Future.scala
+++ b/akka-actor/src/main/scala/akka/dispatch/Future.scala
@@ -337,7 +337,7 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
protected final def resolve[X](source: Either[Throwable, X]): Either[Throwable, X] = source match {
case Left(t: scala.runtime.NonLocalReturnControl[_]) ⇒ Right(t.value.asInstanceOf[X])
- case Left(t: TimeoutException) ⇒ Left(new RuntimeException("Boxed TimeoutException", t))
+ case Left(t: InterruptedException) ⇒ Left(new RuntimeException("Boxed InterruptedException", t))
case _ ⇒ source
}
diff --git a/akka-docs/java/untyped-actors.rst b/akka-docs/java/untyped-actors.rst
index 23b9c18235..2b9a797b57 100644
--- a/akka-docs/java/untyped-actors.rst
+++ b/akka-docs/java/untyped-actors.rst
@@ -280,8 +280,9 @@ If invoked without the sender parameter the sender will be
Ask: Send-And-Receive-Future
----------------------------
-Using ``ask`` will send a message to the receiving Actor asynchronously and
-will immediately return a :class:`Future`:
+Using ``?`` will send a message to the receiving Actor asynchronously and
+will immediately return a :class:`Future` which will be completed with
+an ``akka.actor.AskTimeoutException`` after the specified timeout:
.. code-block:: java
diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst
index 13fe9a7d30..12d368d148 100644
--- a/akka-docs/scala/actors.rst
+++ b/akka-docs/scala/actors.rst
@@ -318,7 +318,8 @@ Ask: Send-And-Receive-Future
----------------------------
Using ``?`` will send a message to the receiving Actor asynchronously and
-will immediately return a :class:`Future`:
+will immediately return a :class:`Future` which will be completed with
+an ``akka.actor.AskTimeoutException`` after the specified timeout:
.. code-block:: scala