public interface ExecInterceptor
The interception methods wrap the rest of the execution.
They receive a continuation (as a Runnable
) that must be called in order for processing to proceed.
The following example (in Groovy) demonstrates using a processing interceptor to time processing.
import ratpack.launch.LaunchConfig import ratpack.launch.LaunchConfigBuilder import ratpack.handling.Context import ratpack.http.Request import ratpack.exec.ExecInterceptor import ratpack.test.embed.LaunchConfigEmbeddedApplication import static ratpack.groovy.Groovy.chain import static ratpack.groovy.test.TestHttpClients.testHttpClient import java.util.concurrent.atomic.AtomicLong class Timer { private final AtomicLong totalCompute = new AtomicLong() private final AtomicLong totalBlocking = new AtomicLong() private boolean blocking private final ThreadLocal<Long> startedAt = new ThreadLocal() { protected Long initialValue() { 0 } } void start(boolean blocking) { this.blocking = blocking startedAt.set(System.currentTimeMillis()) } void stop() { def startedAtTime = startedAt.get() startedAt.remove() def counter = blocking ? totalBlocking : totalCompute counter.addAndGet(startedAtTime > 0 ? System.currentTimeMillis() - startedAtTime : 0) } long getBlockingTime() { totalBlocking.get() } long getComputeTime() { totalCompute.get() } } class ProcessingTimingInterceptor implements ExecInterceptor { final Request request ProcessingTimingInterceptor(Request request) { this.request = request request.register(new Timer()) } void intercept(ExecInterceptor.ExecType type, Runnable continuation) { request.get(Timer).with { start(type == ExecInterceptor.ExecType.BLOCKING) continuation.run() stop() } } } import static ratpack.groovy.test.embed.EmbeddedApplications.embeddedApp def app = embeddedApp { handlers { handler { addExecInterceptor(new ProcessingTimingInterceptor(request)) { next() } } handler { sleep 100 next() } get { sleep 100 blocking { sleep 100 } then { def timer = request.get(Timer) timer.stop() render "$timer.computeTime:$timer.blockingTime" } } } } def client = testHttpClient(app) try { def times = client.getText().split(":")*.toInteger() int computeTime = times[0] int blockingTime = times[1] assert computeTime >= 200 assert blockingTime >= 100 } finally { app.close() }
Modifier and Type | Interface and Description |
---|---|
static class |
ExecInterceptor.ExecType
The execution type (i.e.
|
Modifier and Type | Method and Description |
---|---|
void |
intercept(ExecInterceptor.ExecType execType,
Runnable continuation)
Intercepts the “rest” of the execution on the current thread.
|
void intercept(ExecInterceptor.ExecType execType, Runnable continuation)
The given Runnable
argument represents the rest of the execution to occur on this thread.
This does not necessarily mean the rest of the execution until the work (e.g. responding to a request) is complete.
Execution may involve multiple parallel (but not concurrent) threads of execution because of blocking IO or asynchronous APIs.
All exceptions thrown by this method will be ignored.
execType
- indicates whether this is a compute (e.g. request handling) or blocking IO threadcontinuation
- the “rest” of the execution