Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Made the use of the ordered execution context in Java optional
- Loading branch information
Showing
7 changed files
with
174 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
framework/src/play/src/main/java/play/libs/HttpExecution.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package play.libs; | ||
|
||
import play.Play; | ||
import play.core.Invoker; | ||
import play.core.j.HttpExecutionContext; | ||
import play.core.j.OrderedExecutionContext; | ||
import scala.concurrent.ExecutionContext; | ||
import scala.concurrent.ExecutionContextExecutor; | ||
|
||
/** | ||
* ExecutionContexts that preserve the current thread's context ClassLoader and | ||
* Http.Context. | ||
*/ | ||
public class HttpExecution { | ||
|
||
/** | ||
* An ExecutionContext that executes work on the given ExecutionContext. The | ||
* current thread's context ClassLoader and Http.Context are captured when | ||
* this method is called and preserved for all executed tasks. | ||
*/ | ||
public static ExecutionContextExecutor fromThread(ExecutionContext delegate) { | ||
return HttpExecutionContext.fromThread(delegate); | ||
} | ||
|
||
/** | ||
* An ExecutionContext that executes work on the application's internal | ||
* ActorSystem dispatcher. The current thread's context ClassLoader and | ||
* Http.Context are captured when this method is called and preserved | ||
* for all executed tasks. | ||
*/ | ||
public static ExecutionContextExecutor defaultContext() { | ||
if (Invoker.useOrderedExecutionContext()) { | ||
return orderedContext(); | ||
} else { | ||
return HttpExecutionContext.fromThread(Invoker.executionContext()); | ||
} | ||
} | ||
|
||
private static ExecutionContext orderedExecutionContext = new OrderedExecutionContext(Invoker.system(), 64); | ||
|
||
/** | ||
* An ExecutionContext that executes work for a given Http.Context in the | ||
* same actor each time, ensuring ordered execution of that work. The | ||
* current thread's context ClassLoader and Http.Context are captured when | ||
* this method is called and preserved for all executed tasks. | ||
* | ||
* This ExecutionContext gives the legacy behaviour of Play's F.Promise | ||
* class. | ||
*/ | ||
public static ExecutionContextExecutor orderedContext() { | ||
return HttpExecutionContext.fromThread(orderedExecutionContext); | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
framework/src/play/src/main/scala/play/core/j/HttpExecutionContext.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> | ||
*/ | ||
package play.core.j | ||
|
||
import play.mvc.Http | ||
import scala.concurrent.{ ExecutionContext, ExecutionContextExecutor } | ||
|
||
object HttpExecutionContext { | ||
|
||
/** | ||
* Create an HttpExecutionContext with values from the current thread. | ||
*/ | ||
def fromThread(delegate: ExecutionContext): ExecutionContextExecutor = | ||
new HttpExecutionContext(Thread.currentThread().getContextClassLoader, Http.Context.current.get(), delegate) | ||
|
||
/** | ||
* Create an ExecutionContext that will, when prepared, be created with values from that thread. | ||
*/ | ||
def unprepared(delegate: ExecutionContext) = new ExecutionContext { | ||
def execute(runnable: Runnable) = delegate.execute(runnable) // FIXME: Make calling this an error once SI-7383 is fixed | ||
def reportFailure(t: Throwable) = delegate.reportFailure(t) | ||
override def prepare(): ExecutionContext = fromThread(delegate) | ||
} | ||
} | ||
|
||
/** | ||
* Manages execution to ensure that the given context ClassLoader and Http.Context are set correctly | ||
* in the current thread. Actual execution is performed by a delegate ExecutionContext. | ||
*/ | ||
class HttpExecutionContext(contextClassLoader: ClassLoader, httpContext: Http.Context, delegate: ExecutionContext) extends ExecutionContextExecutor { | ||
def execute(runnable: Runnable) = delegate.execute(new Runnable { | ||
def run() { | ||
val thread = Thread.currentThread() | ||
val oldContextClassLoader = thread.getContextClassLoader | ||
val oldHttpContext = Http.Context.current.get() | ||
thread.setContextClassLoader(contextClassLoader) | ||
Http.Context.current.set(httpContext) | ||
try { | ||
runnable.run() | ||
} finally { | ||
thread.setContextClassLoader(oldContextClassLoader) | ||
Http.Context.current.set(oldHttpContext) | ||
} | ||
} | ||
}) | ||
def reportFailure(t: Throwable) = delegate.reportFailure(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
framework/src/play/src/main/scala/play/core/j/OrderedExecutionContext.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> | ||
*/ | ||
package play.core.j | ||
|
||
import akka.actor.{ Actor, ActorSystem, Props } | ||
import scala.concurrent.ExecutionContext | ||
import play.mvc.Http | ||
import play.api.Logger | ||
|
||
/** | ||
* Executes work in a fixed-sized pool of actors. If an Http.Context is associated | ||
* with the current thread then that id will be used to dispatch work to the same | ||
* actor every time, resulting in ordered execution of work for that context. | ||
* | ||
* The ExecutionContext preserves the execution behaviour of F.Promise from Play. | ||
*/ | ||
class OrderedExecutionContext(actorSystem: ActorSystem, size: Int) extends ExecutionContext { | ||
private val actors = Array.fill(size)(actorSystem.actorOf(Props[OrderedExecutionContext.RunActor])) | ||
|
||
def execute(runnable: Runnable) = { | ||
val httpContext = Http.Context.current.get() | ||
val id: Long = if (httpContext == null) 0L else httpContext.id() | ||
val actor = actors((id % size).toInt) | ||
actor ! runnable | ||
} | ||
|
||
def reportFailure(t: Throwable) = Logger.error("Failure in OrderedExecutionContext", t) | ||
} | ||
|
||
object OrderedExecutionContext { | ||
/** | ||
* Used by the OrderedExecutionContext to run work in an actor. | ||
*/ | ||
class RunActor extends Actor { | ||
def receive = { | ||
case runnable: Runnable => runnable.run() | ||
} | ||
} | ||
} |
Oops, something went wrong.