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

org.eclipse.microprofile.context.ManagedExecutor Maven / Gradle / Ivy

/*
 * Copyright (c) 2018,2019 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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 org.eclipse.microprofile.context;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;

import org.eclipse.microprofile.context.spi.ContextManagerProvider;

import org.eclipse.microprofile.context.spi.ContextManager;

/**
 * 

A container-managed executor service that creates instances of CompletableFuture, * which it backs as the default asynchronous execution facility, both for the * CompletableFuture itself as well as all dependent stages created from it, * as well as all dependent stages created from those, and so on.

* *

Example usage:

*
 * ManagedExecutor executor = ManagedExecutor.builder().propagated(ThreadContext.APPLICATION).cleared(ThreadContext.ALL_REMAINING).build();
 * ...
 * CompletableFuture<Integer> future = executor
 *    .supplyAsync(supplier)
 *    .thenApplyAsync(function1)
 *    .thenApply(function2)
 *    ...
 * 
 * 
* *

This specification allows for managed executors that propagate thread context as well as for * those that do not, which might offer better performance. If thread context propagation is * desired only for specific stages, or if you wish to override thread context propagation for * specific stages, the ThreadContext.contextual* API methods can be used to * propagate thread context to individual actions.

* *

Example of single action with context propagation:

*
 * CompletableFuture<?> future = executor
 *    .runAsync(runnable1)
 *    .thenRun(threadContext.contextualRunnable(runnable2))
 *    .thenRunAsync(runnable3)
 *    ...
 * 
* *

Managed executors that capture and propagate thread context must do so in a consistent * and predictable manner, which is defined as follows,

* *
    *
  • * If the supplied action is already contextual (for example, * threadContext.contextualFunction(function1)), * then the action runs with the already-captured context. *
  • *
  • * Otherwise, each type of thread context is either {@link Builder#propagated propagated} from the thread * that creates the completion stage or marked to be {@link Builder#cleared cleared}, according to the * configuration of the managed executor that is the default asynchronous execution facility * for the new stage and its parent stage. In the case that a managed executor is supplied * as the executor argument to a *Async method, the supplied * managed executor is used to run the action, but not to determine thread context * propagation and clearing. *
  • *
* *

Each type of thread context is applied (either as cleared or as previously captured) * to the thread that runs the action. The applied thread context is removed after the action * completes, whether successfully or exceptionally, restoring the thread's prior context.

* *

When dependent stages are created from the completion stage, and likewise from any dependent stages * created from those, and so on, thread context is captured or cleared in the same manner. * This guarantees that the action performed by each stage always runs under the thread context * of the code that creates the stage, unless the user explicitly overrides this by supplying a * pre-contextualized action.

* *

Thread context is similarly captured, cleared, applied, and afterward restored for the * ExecutorService methods: * execute, invokeAll, invokeAny, submit *

* *

This interface is intentionally kept compatible with ManagedExecutorService, * with the hope that its methods might one day be contributed to that specification.

* *

Managed executors that are created with the {@link Builder} or created for * injection into applications via CDI must support the life cycle methods, including: * awaitTermination, isShutdown, isTerminated, shutdown, shutdownNow. * The application must invoke shutdown or shutdownNow to terminate * the life cycle of each managed executor that it creates, once the managed executor is * no longer needed. When the application stops, the container invokes shutdownNow * for any remaining managed executors that the application did not already shut down. * The shutdown methods signal the managed executor that it does not need to remain active to * service subsequent requests and allow the container to properly clean up associated resources.

* *

Managed executors which have a life cycle that is scoped to the container, * including those obtained via mechanisms defined by EE Concurrency, must raise * IllegalStateException upon invocation of the aforementioned life cycle methods, * in order to preserve compatibility with that specification.

* *

Managed executors can forward all contextualised async tasks to a backing executor service * if set with {@link ContextManager.Builder#withDefaultExecutorService(ExecutorService)}. * Otherwise, a new backing executor service may be created, unless the implementation has its own * default executor service.

*/ public interface ManagedExecutor extends ExecutorService { /** * Creates a new {@link Builder} instance. * * @return a new {@link Builder} instance. */ public static Builder builder() { return ContextManagerProvider.instance().getContextManager().newManagedExecutorBuilder(); } /** *

Builder for {@link ManagedExecutor} instances.

* *

Example usage:

*
 ManagedExecutor executor = ManagedExecutor.builder()
     *                                                  .maxAsync(5)
     *                                                  .maxQueued(20)
     *                                                  .propagated(ThreadContext.SECURITY)
     *                                                  .build();
     * ...
     * 
*/ public interface Builder { /** *

Builds a new {@link ManagedExecutor} with the configuration * that this builder represents as of the point in time when this method * is invoked.

* *

After {@link #build} is invoked, the builder instance retains its * configuration and may be further updated to represent different * configurations and build additional {@link ManagedExecutor} * instances.

* *

All created instances of {@link ManagedExecutor} are destroyed * when the application is stopped. The container automatically shuts down these * managed executors.

* * @return new instance of {@link ManagedExecutor}. * @throws IllegalStateException for any of the following error conditions *
    *
  • if one or more of the same context types appear in both the * {@link #cleared} set and the {@link #propagated} set
  • *
  • if a thread context type that is configured to be * {@link #cleared} or {@link #propagated} is unavailable
  • *
  • if context configuration is neither specified on the builder * nor via MicroProfile Config, and the builder implementation lacks * vendor-specific defaults of its own.
  • *
  • if more than one provider provides the same thread context * {@link org.eclipse.microprofile.context.spi.ThreadContextProvider#getThreadContextType type} *
  • *
*/ ManagedExecutor build(); /** *

Defines the set of thread context types to clear from the thread * where the action or task executes. The previous context is resumed * on the thread after the action or task ends.

* *

This set replaces the cleared set that was previously * specified on the builder instance, if any.

* *

For example, if the user specifies * {@link ThreadContext#TRANSACTION} in this set, then a transaction * is not active on the thread when the action or task runs, such * that each action or task is able to independently start and end * its own transactional work.

* *

{@link ThreadContext#ALL_REMAINING} is automatically appended to the * set of cleared context if the {@link #propagated} set does not include * {@link ThreadContext#ALL_REMAINING}.

* *

Constants for specifying some of the core context types are provided * on {@link ThreadContext}. Other thread context types must be defined * by the specification that defines the context type or by a related * MicroProfile specification.

* *

The MicroProfile Config property, mp.context.ManagedExecutor.cleared, * establishes a default that is used if no value is otherwise specified. * The value of the MicroProfile Config property can be the empty string * or a comma separated list of context type constant values.

* * @param types types of thread context to clear from threads that run * actions and tasks. * @return the same builder instance upon which this method is invoked. */ Builder cleared(String... types); /** *

Defines the set of thread context types to capture from the thread * that creates a dependent stage (or that submits a task) and which to * propagate to the thread where the action or task executes.

* *

This set replaces the propagated set that was * previously specified on the builder instance, if any.

* *

Constants for specifying some of the core context types are provided * on {@link ThreadContext}. Other thread context types must be defined * by the specification that defines the context type or by a related * MicroProfile specification.

* *

The MicroProfile Config property, mp.context.ManagedExecutor.propagated, * establishes a default that is used if no value is otherwise specified. * The value of the MicroProfile Config property can be the empty string * or a comma separated list of context type constant values.

* *

Thread context types which are not otherwise included in this set * are cleared from the thread of execution for the duration of the * action or task.

* * @param types types of thread context to capture and propagate. * @return the same builder instance upon which this method is invoked. */ Builder propagated(String... types); /** *

Establishes an upper bound on the number of async completion stage * actions and async executor tasks that can be running at any given point * in time. There is no guarantee that async actions or tasks will start * running immediately, even when the maxAsync constraint has * not get been reached. Async actions and tasks remain queued until * the ManagedExecutor starts executing them.

* *

The default value of -1 indicates no upper bound, * although practically, resource constraints of the system will apply. * You can switch the default by specifying the MicroProfile Config * property, mp.context.ManagedExecutor.maxAsync.

* * @param max upper bound on async completion stage actions and executor tasks. * @return the same builder instance upon which this method is invoked. * @throws IllegalArgumentException if max is 0 or less than -1. */ Builder maxAsync(int max); /** *

Establishes an upper bound on the number of async actions and async tasks * that can be queued up for execution. Async actions and tasks are rejected * if no space in the queue is available to accept them.

* *

The default value of -1 indicates no upper bound, * although practically, resource constraints of the system will apply. * You can switch the default by specifying the MicroProfile Config * property, mp.context.ManagedExecutor.maxQueued.

* * @param max upper bound on async actions and tasks that can be queued. * @return the same builder instance upon which this method is invoked. * @throws IllegalArgumentException if max is 0 or less than -1. */ Builder maxQueued(int max); } /** *

Returns a new CompletableFuture that is already completed with the specified value.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param value result with which the completable future is completed. * @param result type of the completable future. * @return the new completable future. */ CompletableFuture completedFuture(U value); /** *

Returns a new CompletionStage that is already completed with the specified value.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param value result with which the completable future is completed. * @param result type of the completion stage. * @return the new completion stage. */ CompletionStage completedStage(U value); /** *

Returns a new CompletableFuture that is already exceptionally completed with the specified Throwable.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param ex exception or error with which the completable future is completed. * @param result type of the completable future. * @return the new completable future. */ CompletableFuture failedFuture(Throwable ex); /** *

Returns a new CompletionStage that is already exceptionally completed with the specified Throwable.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param ex exception or error with which the stage is completed. * @param result type of the completion stage. * @return the new completion stage. */ CompletionStage failedStage(Throwable ex); /** *

Returns a new incomplete CompletableFuture.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param result type of the completion stage. * @return the new completion stage. */ CompletableFuture newIncompleteFuture(); /** *

Returns a new CompletableFuture that is completed by a task running in this executor * after it runs the given action.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param runnable the action to run before completing the returned completion stage. * @return the new completion stage. */ CompletableFuture runAsync(Runnable runnable); /** *

Returns a new CompletableFuture that is completed by a task running in this executor * after it runs the given action.

* *

This executor is the default asynchronous execution facility for the new completion stage * that is returned by this method and all dependent stages that are created from it, * and all dependent stages that are created from those, and so forth.

* * @param result type of the supplier and completion stage. * @param supplier an action returning the value to be used to complete the returned completion stage. * @return the new completion stage. */ CompletableFuture supplyAsync(Supplier supplier); /** *

* Returns a new CompletableFuture that is completed by the completion of the * specified stage. *

* *

* The new completable future is backed by the ManagedExecutor upon which copy is invoked, * which serves as the default asynchronous execution facility * for the new stage and all dependent stages created from it, and so forth. *

* *

* When dependent stages are created from the new completable future, thread context is captured * and/or cleared by the ManagedExecutor. This guarantees that the action * performed by each stage always runs under the thread context of the code that creates the stage, * unless the user explicitly overrides by supplying a pre-contextualized action. *

* *

* Invocation of this method does not impact thread context propagation for the supplied * completable future or any dependent stages created from it, other than the new dependent * completable future that is created by this method. *

* * @param completable future result type. * @param stage a completable future whose completion triggers completion of the new completable * future that is created by this method. * @return the new completable future. */ CompletableFuture copy(CompletableFuture stage); /** *

* Returns a new CompletionStage that is completed by the completion of the * specified stage. *

* *

* The new completion stage is backed by the ManagedExecutor upon which copy is invoked, * which serves as the default asynchronous execution facility * for the new stage and all dependent stages created from it, and so forth. *

* *

* When dependent stages are created from the new completion stage, thread context is captured * and/or cleared by the ManagedExecutor. This guarantees that the action * performed by each stage always runs under the thread context of the code that creates the stage, * unless the user explicitly overrides by supplying a pre-contextualized action. *

* *

* Invocation of this method does not impact thread context propagation for the supplied * stage or any dependent stages created from it, other than the new dependent * completion stage that is created by this method. *

* * @param completion stage result type. * @param stage a completion stage whose completion triggers completion of the new stage * that is created by this method. * @return the new completion stage. */ CompletionStage copy(CompletionStage stage); /** * Returns a ThreadContext which has the same propagation settings as this ManagedExecutor, * which uses this ManagedExecutor as its default executor. * * @return a ThreadContext with the same propagation settings as this ManagedExecutor. */ ThreadContext getThreadContext(); }