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();
}