All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.exec.ExecInterceptor Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ratpack.exec;

/**
 * Intercepts execution, primarily for traceability and recording metrics.
 * 

* The interception methods wrap the rest of the execution. * They receive a continuation (as a {@link Runnable}) that must be called in order for processing to proceed. *

* Request handling execution can be intercepted by the {@link ExecControl#addInterceptor(ExecInterceptor, ratpack.func.NoArgAction)} method. *

{@code
 * import ratpack.exec.ExecInterceptor;
 * import ratpack.http.Request;
 * import ratpack.test.handling.RequestFixture;
 * import ratpack.test.handling.HandlingResult;
 *
 * import java.util.concurrent.atomic.AtomicLong;
 *
 * 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 final AtomicLong totalCompute = new AtomicLong();
 *     private final AtomicLong totalBlocking = new AtomicLong();
 *     private boolean blocking;
 *
 *     private final ThreadLocal startedAt = ThreadLocal.withInitial(() -> 0l);
 *
 *     public void start(boolean blocking) {
 *       this.blocking = blocking;
 *       startedAt.set(System.currentTimeMillis());
 *     }
 *
 *     public void stop() {
 *       long startedAtTime = startedAt.get();
 *       startedAt.remove();
 *       AtomicLong counter = blocking ? totalBlocking : totalCompute;
 *       counter.addAndGet(startedAtTime > 0 ? System.currentTimeMillis() - startedAtTime : 0);
 *     }
 *
 *     public long getBlockingTime() {
 *       return totalBlocking.get();
 *     }
 *
 *     public long getComputeTime() {
 *       return totalCompute.get();
 *     }
 *   }
 *
 *   public static class ProcessingTimingInterceptor implements ExecInterceptor {
 *     private final Request request;
 *
 *     public ProcessingTimingInterceptor(Request request) {
 *       this.request = request;
 *       request.add(new Timer());
 *     }
 *
 *     public void intercept(ExecInterceptor.ExecType type, Runnable continuation) {
 *       Timer timer = request.get(Timer.class);
 *       timer.start(type.equals(ExecInterceptor.ExecType.BLOCKING));
 *       continuation.run();
 *       timer.stop();
 *     }
 *   }
 *
 *   public static void main(String[] args) throws Exception {
 *     HandlingResult result = RequestFixture.requestFixture().handleChain(chain -> chain
 *         .handler(context ->
 *             context.addInterceptor(new ProcessingTimingInterceptor(context.getRequest()), context::next)
 *         )
 *         .handler(context -> {
 *           sleep(100);
 *           context.blocking(() -> {
 *             sleep(100);
 *             return "foo";
 *           }).then(string -> {
 *             sleep(100);
 *             context.render(string);
 *           });
 *         })
 *     );
 *
 *     assertEquals("foo", result.rendered(String.class));
 *     
 *     Timer timer = result.getRequestRegistry().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 {@link ExecControl#addInterceptor(ExecInterceptor, ratpack.func.NoArgAction)}. * * @see Execution * @see ExecControl#addInterceptor(ExecInterceptor, ratpack.func.NoArgAction) */ public interface ExecInterceptor { /** * The execution type (i.e. type of thread). */ enum ExecType { /** * The execution is performing blocking IO. */ BLOCKING, /** * The execution is performing computation (i.e. it is not blocking) */ COMPUTE } /** * Intercepts the “rest” of the execution on the current thread. *

* The given {@code 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. * @param execType indicates whether this is a compute (e.g. request handling) or blocking IO thread * @param continuation the “rest” of the execution */ void intercept(ExecType execType, Runnable continuation); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy