MicroProfile Community

MicroProfile Context Propagation 1.0 is Now Available

By July 9, 2019 No Comments

MicroProfile Context Propagation 1.0 is now available as a standalone release, i.e. outside the MicroProfile umbrella/platform release.

MicroProfile Context Propagation enables CompletionStages and CompletableFutures, such as those returned by MicroProfile Fault Tolerance @Asynchronous, to reliably run with predictable thread context, and guards against unintentional donation of context from threads that perform operations which cause completion stage actions to run inline.  Completion stages enable you to create chains of dependent actions that react to the completion of actions upon which they depend.  This very useful and powerful mechanism comes with the trade-off of inconsistent thread context, because a dependent stage action may run on any of a number of different threads, each with potentially different context.  The MicroProfile Context Propagation specification eliminates the inconsistency by providing ways to enforce consistent thread context.

Usage Scenario in Conjunction with MicroProfile Fault Tolerance

Have you ever wanted to return a chain of dependent stages from a MicroProfile Fault Tolerance @Asynchronous method where the dependent stages are guaranteed to run with the same context that is available to your Asynchronous method?  With MicroProfile Context Propagation, this is now possible.  Instead of creating the initial stage with the JDK’s built-in CompletableFuture, create it with a ManagedExecutor, as shown in the following example:

    @Asynchronous
    public Future<Integer> beginComputation() {
        CompletableFuture<Integer> future = managedExecutor.newIncompleteFuture();
        ...
        return future.thenApply(actionThatRequiresContext)
                     .thenApply(anotherActionThatRequiresContext);
    }

or, if using CompletableFuture that isn’t thread context aware, then use ThreadContext to pre-contextualize a single action, as follows:

    @Asynchronous
    public Future<Integer> beginComputation() {
        CompletableFuture<Integer> future = new CompletableFuture<Integer>();
        ...
        return future.thenApply(threadContext.contextalFunction(actionThatRequiresContext))
                     .thenApply(actionThatDoesNotRequireContext);
    }

Application Programming Interface (API) and Service Provider Interface (SPI)

Managed Executor

ManagedExecutor extends the concept of the Java EE/Jakarta EE ManagedExecutorService (absent any direct dependency) with the ability to create CompletionStages/CompletableFutures that are backed by the managed executor, such that all dependent stage actions, whether asynchronous or inline, run with context that is captured from the thread which creates the dependent stage (or under empty/cleared context if so configured).

Thread Context

ThreadContext refines the concept of the Java EE/Jakarta EE ContextService (absent any direct dependency) to optimize and provide a more usable mechanism for granular control over the contextualization of specific CompletableFuture/CompletionStage actions. It does this by wrapping context around core functional interfaces (such as Function, Supplier, Runnable) which can be used in combination any CompletionStage/CompletableFuture, to create pre-contextualized dependent stage actions that run with context that is captured from the thread which requests the contextualization. This makes it possible to have deterministic and reliable thread context for new dependent stage actions, even when using a standard CompletableFuture/CompletionStage which otherwise lacks thread context awareness.

Both of the above provide a fluent builder pattern for the configuration and creation of new instances, allowing the user to more granularly customize how thread context propagation and clearing is done.

Plugging in Third Party Context Types

MicroProfile Context Propagation also includes an SPI to standardize how to plug in third-party custom providers of thread context, which are then cleared, captured, propagated and restored according to the standard contract defined by ManagedExecutor and ThreadContext for context propagation and clearing.

Examples

ManagedExecutor Example

The following example uses ManagedExecutor to cause the current thread’s CDI context and application context (such as java:comp namespace) to be made available to all of the dependent stage actions:

    ManagedExecutor executor = ManagedExecutor.builder()
        .propagated(ThreadContext.CDI, ThreadContext.APPLICATION)
        .build();
    ...
    CompletableFuture stage = executor
        .supplyAsync(supplier1)
        .thenApplyAsync(function1)
        .thenApply(function2);

ThreadContext Example

The following example uses ThreadContext for granular contextualization of a single stage, to which application context is propagated (allowing the lookup) and security and transaction context are cleared, and all other thread context types types are ignored and left in place on the thread:

    ThreadContext threadContext = ThreadContext.builder()
        .propagated(ThreadContext.APPLICATION)
        .cleared(ThreadContext.SECURITY, ThreadContext.TRANSACTION)
        .unchanged(ThreadContext.ALL_REMAINING)
        .build();
    ...
    Function getItemCost = threadContext.contextualFunction(id -> {
        // java:comp, java:module, java:app lookups require the application's context
        DataSource ds = InitialContext.doLookup("java:app/env/jdbc/ds1");
        ...
    });
    unmanagedStage4 = unmanagedStage1.thenApply(getProductId)
                                     .thenApply(getItemCost)
                                     .thenApply(addToTotal);

Maven Coordinates

    <dependency>
        <groupId>org.eclipse.microprofile.context-propagation</groupId>
        <artifactId>microprofile-context-propagation-api</artifactId>
        <version>1.0</version>
    </dependency>

Available Implementations

There are currently two implementations of MicroProfile Context Propagation: OpenLiberty and Quarkus.

Further information

For more information about MicroProfile Context Propagation 1.0, please visit its GitHub release page.

 

 

Nathan Rauh

Author Nathan Rauh

More posts by Nathan Rauh

Leave a Reply