Permalink
Browse files

optionally prevent a blocking actor from preventing quick reloading

  • Loading branch information...
1 parent 9595312 commit 5482d920ddca0a73d1bfd40e03eaff391e324b15 @jamesward jamesward committed Feb 12, 2014
@@ -3,10 +3,12 @@
*/
package play.api.libs.concurrent
+import java.util.concurrent.{ TimeUnit, TimeoutException }
import play.api._
import play.core.ClosableLazy
import scala.concurrent.Future
import akka.actor.ActorSystem
+import scala.concurrent.duration._
import com.typesafe.config._
@@ -49,7 +51,20 @@ class AkkaPlugin(app: Application) extends Plugin {
protected def close(systemToClose: ActorSystem) = {
Play.logger.info("Shutdown application default Akka system.")
systemToClose.shutdown()
- systemToClose.awaitTermination()
+
+ app.configuration.getMilliseconds("play.akka.shutdown-timeout") match {
+ case Some(timeout) =>
+ try {
+ systemToClose.awaitTermination(Duration(timeout, TimeUnit.MILLISECONDS))
+ } catch {
+ case te: TimeoutException =>
+ // oh well. We tried to be nice.
+ Play.logger.info(s"Could not shutdown the Akka system in $timeout milliseconds. Giving up.")
+ }
+ case None =>
+ // wait until it is shutdown
+ systemToClose.awaitTermination()
+ }
}
}
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
+ */
+package play.api.libs.concurrent
+
+import org.specs2.mutable._
+import play.api.libs._
+import play.api.FakeApplication
+import akka.actor.{Props, Actor}
+import java.util.Date
+
+object AkkaSpec extends Specification {
+
+ // returns the time it took to stop the Akka plugin in milliseconds
+ def testBlockingActor(app: play.api.Application): Long = {
+ val plugin = new AkkaPlugin(app)
+
+ val blockingActor = plugin.applicationSystem.actorOf(Props[BlockingActor])
+
+ blockingActor ! Block
+
+ val startTime = System.nanoTime()
+
+ plugin.onStop()
+
+ val endTime = System.nanoTime()
+
+ (endTime - startTime) / 1000 / 1000
+ }
+
+ "AkkaPlugin with a blocking Actor" should {
+ "by default wait until the blocking actor is terminated" in {
+ val totalTime = testBlockingActor(FakeApplication())
+
+ // the actor blocks shutdown for 1 second
+ totalTime must be between (1000, 1400)
+ }
+ "be able to be restarted when the Actor is blocking if the config is provided" in {
+ val app = FakeApplication(Map("play.akka.shutdown-timeout" -> "500ms"))
+ val totalTime = testBlockingActor(app)
+
+ // the actor blocks for 30 seconds but we should be back here in around 500ms
+ totalTime must be between (500, 900)
+ }
+ }
+
+}
+
+class BlockingActor extends Actor {
+
+ def receive = {
+ case Block =>
+ context.system.log.info("BlockingActor is now blocking for 30 seconds")
+ Thread.sleep(1000)
+ context.system.log.info("BlockingActor is done blocking")
+ }
+
+}
+
+case object Block

0 comments on commit 5482d92

Please sign in to comment.