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.
Request handling execution can be intercepted by the Execution.addInterceptor(ExecInterceptor, ratpack.func.Block)
method.
import ratpack.exec.ExecInterceptor;
import ratpack.exec.Execution;
import ratpack.exec.Blocking;
import ratpack.exec.ExecResult;
import ratpack.func.Block;
import ratpack.test.exec.ExecHarness;
import static java.lang.Thread.sleep;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class Example {
public static class Timer {
private long totalCompute;
private long totalBlocking;
private boolean blocking;
private long startedAt;
public void start(boolean blocking) {
this.blocking = blocking;
startedAt = System.currentTimeMillis();
}
public void stop() {
long duration = System.currentTimeMillis() - startedAt;
if (blocking) {
totalBlocking += duration;
} else {
totalCompute += duration;
}
}
public long getBlockingTime() {
return totalBlocking;
}
public long getComputeTime() {
return totalCompute;
}
}
public static class ProcessingTimingInterceptor implements ExecInterceptor {
public void intercept(Execution execution, ExecInterceptor.ExecType type, Block continuation) throws Exception {
Timer timer = execution.maybeGet(Timer.class).orElse(null);
if (timer == null) { // this is the first execution segment
timer = new Timer();
execution.add(Timer.class, timer);
}
timer.start(type.equals(ExecInterceptor.ExecType.BLOCKING));
try {
continuation.execute();
} finally {
timer.stop();
}
}
}
public static void main(String[] args) throws Exception {
ExecResult<String> result = ExecHarness.yieldSingle(
r -> r.add(new ProcessingTimingInterceptor()), // add the interceptor to the registry
e -> {
Thread.sleep(100);
return Blocking.get(() -> {
Thread.sleep(100);
return "foo";
})
.map(s -> {
Thread.sleep(100);
return s.toUpperCase();
});
}
);
assertEquals("FOO", result.getValue());
Timer timer = result.getRegistry().get(Timer.class);
assertTrue(timer.getBlockingTime() >= 100);
assertTrue(timer.getComputeTime() >= 200);
}
}
For other types of executions (e.g. background jobs), the interceptor can be registered via Execution.addInterceptor(ExecInterceptor, ratpack.func.Block)
.Modifier and Type | Interface and Description |
---|---|
static class |
ExecInterceptor.ExecType
The execution type (i.e.
|
Modifier and Type | Method and Description |
---|---|
void |
intercept(Execution execution,
ExecInterceptor.ExecType execType,
Block continuation)
Intercepts the “rest” of the execution on the current thread.
|
void intercept(Execution execution, ExecInterceptor.ExecType execType, Block continuation) throws Exception
The given action 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.
execution
- the execution who's segment is being interceptedexecType
- indicates whether this is a compute (e.g. request handling) segment or blocking segmentcontinuation
- the “rest” of the executionException
- any