eclipse / microprofile-context-propagation

Apache License 2.0
33 stars 23 forks source link

// // 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. // image:https://img.shields.io/maven-central/v/org.eclipse.microprofile.context-propagation/microprofile-context-propagation-api.svg[link="http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.microprofile.context-propagation%22%20AND%20a%3A%22microprofile-context-propagation-api%22"] image:https://javadoc.io/badge/org.eclipse.microprofile.context-propagation/microprofile-context-propagation-api.svg[ link="https://javadoc.io/doc/org.eclipse.microprofile.context-propagation/microprofile-context-propagation-api"] image:https://badges.gitter.im/eclipse/microprofile-concurrency.svg[link="https://gitter.im/eclipse/microprofile-concurrency"]

[[microprofile-context-propagation]] = MicroProfile Context Propagation

:toc:

[[introduction]] Introduction


The proposal introduces APIs for obtaining CompletableFutures that are
backed by managed threads (threads that are managed by the container),
with the ability to capture context from the thread that creates the
CompletableFuture and apply it when running the CompletionStage action.

[[documentation]]
Documentation

For links to the latest Javadoc and specification document, see the link:https://github.com/eclipse/microprofile-context-propagation/releases/latest[latest release].

[[motivation]] Motivation


When using a reactive model with dependent stages which execute upon
completion of prior stages, the context under which dependent stages
execute is unpredictable.  Dependent stages might run with the
context of a thread that awaits completion, or the context of a
previous stage that completed and triggered the dependent stage,
or with no/undefined context at all.  Existing solutions for
transferring thread context, such as the EE Concurrency Utilities
ContextService, are difficult to use and require a lot of boilerplate
code.  This spec makes it possible for thread context propagation to
easily be done in a type-safe way, keeping boilerplate code to a
minimum, as well as allowing for thread context propagation to be
done automatically when using a CompletableFuture.

It is also important that CompletableFutures and their dependent
stages, and dependent stages created by those stages, and so on,
all run on threads that are known by the container and properly
managed by it.  This spec makes it possible to do so by providing
an API by which the user obtains managed CompletableFuture instances
from a managed executor.

The above are proposed to be addressed within EE Concurrency under
https://github.com/eclipse-ee4j/concurrency-api/issues/40[EE Concurrency Issue 40],
however, it will be a while before Jakarta EE specs are able to
make progress, leading us to address this first in MicroProfile.

Goals

* Proper management of CompletableFuture threads by the container.
* Mechanism for thread context propagation to CompletableFuture
actions that reduces the need for boilerplate code.
* Full compatibility with EE Concurrency spec, such that proposed
interfaces can eventually be seamlessly merged into EE Concurrency.

[[proposed-solution]]
Proposed solution

This spec introduces two interfaces that contain methods that we hope will eventually be added to Jakarta EE Concurrency.

The interface, org.eclipse.microprofile.concurrent.ManagedExecutor, provides methods for obtaining managed instances of CompletableFuture which are backed by the managed executor as the default asynchronous execution facility and the default mechanism of defining thread context propagation. Similar to EE Concurrency's ManagedExecutorService, the MicroProfile ManagedExecutor also implements the Java SE java.util.concurrent.ExecutorService interface, using managed threads when asynchronous invocation is required and disallowing the same life cycle methods as ManagedExecutorService. It is intended that ManagedExecutor methods will one day be added to ManagedExecutorService, and for a single implementation to be capable of simultaneously implementing both interfaces, both currently as well as after adoption into Jakarta EE.

A second interface, org.eclipse.microprofile.concurrent.ThreadContext, provides methods for individually contextualizing dependent stage actions. This gives the user more fine-grained control over the capture and propagation of thread context. It is intended that ThreadContext methods will one day be added to EE Concurrency's ContextService and for a single implementation to be capable of simultaneously implementing both interfaces, both currently as well as after adoption into Jakarta EE.

[[builders]] Builders ^^^^^^^^^

It shall be possible to build instances of ManagedExecutor and ThreadContext via a fluent builder pattern, for example:

[source,java]

ManagedExecutor executor = ManagedExecutor.builder() .maxAsync(5) .propagated(ThreadContext.CDI, ThreadContext.APPLICATION) .build();

ThreadContext threadContext = ThreadContext.builder() .propagated(ThreadContext.SECURITY) .build(); ... CompletableFuture stage = executor .supplyAsync(supplier1) .thenApplyAsync(function1) .thenApply(function2) .thenApply(threadContext.contextualFunction(function3));

[[injection]] Injection ^^^^^^^^^

The builders can be used in combination with standard CDI producers and injection to define and manage single instances across an application:

[source,java]

@Produces @ApplicationScoped @MyQualifier createExecutor() { return ManagedExecutor.builder() .propagated(ThreadContext.SECURITY) .cleared(ThreadContext.ALL_REMAINING) .build(); }

disposeExecutor(@Disposes @MyQualifier exec) { exec.shutdownNow(); }

... // CDI injection point, possibly in another bean,

@Inject @MyQualifier ManagedExecutor executor;

[[context-propagation-defaults]] Context Propagation Defaults ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The MicroProfile Context Propagation specification does not define a default set of context types that must be propagated in the absence of explicit configuration. Implementations of MicroProfile Context Propagation are encouraged to default to propagating all available context types unless doing so would cause unexpected behavior. For consistency with the Jakarta/Java EE Concurrency programming model, transaction context may be cleared by default, rather than propagated by default, by implementations that are also Jakarta/Java EE application servers.

// TODO: insert links to implementation defaults here, once available

You can define your own defaults for context propagation via MicroProfile Config properties. For example,

[source,java]

mp.context.ManagedExecutor.cleared=Transaction mp.context.ManagedExecutor.propagated=Remaining mp.context.ThreadContext.cleared=Transaction mp.context.ThreadContext.propagated=Remaining

[[spi-for-context-providers]] SPI for Thread Context Providers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The initial release of EE Concurrency assumed single monolithic implementations of all specifications together that could rely on vendor-specific internals to achieve context propagation. However, in practice, open source implementations of various specs are often pieced together into a comprehensive solution.

The thread context provider SPI is defined to bridge the gap, allowing any provider of thread context to publish and make available the type of thread context it supports, following a standard and predictable pattern that can be relied upon by a MicroProfile Context Propagation implementation, enabling it to facilitate the inclusion of any generic thread context alongside the spec defined thread context types that it captures and propagates.

With this model, the provider of thread context implements the org.eclipse.microprofile.concurrent.spi.ThreadContextProvider interface and packages it in a way that makes it available to the ServiceLoader. ThreadContextProvider identifies the thread context type and provides a way to capture snapshots of thread context as well as for applying empty/cleared context to threads.

[[contributing]] Contributing


Do you want to contribute to this project? link:CONTRIBUTING.adoc[Find out how you can help here].