Re: Clarification regarding ManagedExecutorService in Rx Client


Andy McCright
 

Hi Markus,
 
On the surface, I agree.  I think that the "fix" should probably go in the Concurrency spec.  The fix in this case is an implementation of the CompletionStage interface that is friendly to Managed executors.
 
The reasons I bring it up in JAX-RS are:
(1) The JAX-RS 2.1 spec mandates the use of Managed executors when the host server provides the Concurrency spec implementation (see section 5.8).
(2) As far as I know, JAX-RS 2.1 is the only EE8 spec to use the CompletionStage interface.  In my example, the CompletionStage is returned from a JAX-RS API, not the CompletableFuture API (which is in Java SE - and has no concept of Managed executors).
 
My colleague, Nathan Rauh, is bringing this same issue to the attention of the Concurrency spec EG.  I think the right answer is for the Concurrency spec to provide a CompletionStage implementation that can handle Managed executors, and then for the JAX-RS spec to mandate that when the Concurrency spec is in play, it MUST use the Concurrency spec's CompletionStage implementation.
 
 
Hope that helps,
 
Andy


J. Andrew McCright
IBM WebSphere Development
+1 507 253 7448
TL 553-7448
andymc@...
 
 

----- Original message -----
From: "Markus KARG" <markus@...>
Sent by: jaxrs-spec@javaee.groups.io
To: jaxrs-spec@javaee.groups.io
Cc:
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client
Date: Wed, Dec 13, 2017 12:43 PM
 

Andy,

 

I need to say that your question does not seem to be particularly related to JAX-RS: The question you ask would be the exact same even if you do not use JAX-RS at all, but simply do CompletionStage stage = CompletableFuture.supplyAsync(...other-http-Client-here…)instead. Hence I do not see why it should be up to the JAX-RS specification in particular to declare a solution? What we provide with JAX-RS 2.1 is only the ability to inject Executors and return CompletionStage, mostly for the sake of simplicity. The intention never was to solve such questions which also would exist without JAX-RS.

 

-Markus

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Andy McCright
Sent: Mittwoch, 13. Dezember 2017 17:29
To: jaxrs-spec@javaee.groups.io
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

Hi Markus,

 

Thanks for the response.  I understand that open sourcing of Java EE to Eclipse has put things in a sort of "limbo", so I'll just try to focus on the technical aspects of this thread.

 

This example might help illustrate the problem better - suppose that we have a Java EE application that uses a servlet and two EJBs:

 

in Servlet:

@Resource

ExecutorService nonManagedExecutor;

 

// initial Rx request

CompletionStage stage = clientBuilder.executorService(managedExecService).build().target(uri).request().rx().method(...);

// first "stage" task

stage.thenRunAsync( new Runnable() {

    public void run() {

        Context ctx = new InitialContext();

        SomeObject x = ctx.lookup("java:comp/env/somethingSpecificToThisModule");

        ...

    }, nonManagedExecutor);

}

 

ejb1.syncMethod(stage);

ejb2.asyncMethod(stage);

 

 

in EJB 1:

@Resource

ManagedExecutorService managedExecutorService;

 

@RunAs("Admin")

public void syncMethod(CompletionStage stage) {

    stage.thenRunAsync( new Runnable() {

        public void run() {

            Context ctx = new InitialContext();

            SomeOtherObject x = ctx.lookup("java:comp/env/somethingSpecificToThisEJB");

            // do some work that only the Admin role can perform

            ...

        }

    }, managedExecutorService);

}

 

in EJB 2:

@Resource

ManagedExecutorService managedExecutorService;

 

@Asynchronous

public Future<Something> asyncMethod(CompletionStage stage) {

    stage.thenRunAsync( new Runnable() {

        public void run() {

            Context ctx = new InitialContext();

            SomeThirdObject x = ctx.lookup("java:comp/env/somethingSpecificToThisOtherEJB");

            ...

        }

    }, managedExecutorService);

}

 

So, in this example, we've got a servlet that has one set of contexts (security, transaction, java:* naming, metadata, etc.), and two EJBs with separate contexts - one runs as the Admin role, one is asynchronous, so it runs on a separate thread.  Each of these components adds a new stage with a specified ManagedExecutorService.  Which contexts should these runnables execute with?  

 

In EJB 1, the only way the app will function is if security context from EJB 1 is used in that method's Runnable, but is that the intent of the spec?  Or should EJB 1's Runnable use the Servlet's context since that is where the CompletionStage was first created?  Or should it use the context of the previous stage (i.e. the Runnable from inside the Servlet's method - which doesn't transfer context since it is a non-managed executor service)?

 

I think the most intuitive answer is that the context should be transferred from the thread calling the "thenRunAsync" method. Otherwise in the example above, the Runnables in the EJBs have no idea what context they are executing with - i.e. a different servlet might have different contexts when invoking the EJBs.

 

Does that make sense?  Does anybody have other suggestions for what the proper behavior of the CompletionStage should be?

 

Thanks again,

 

Andy


J. Andrew McCright
IBM WebSphere Development
+1 507 253 7448
TL 553-7448
andymc@...

 

 

----- Original message -----
From: "Markus KARG" <markus@...>
Sent by: jaxrs-spec@javaee.groups.io
To: jaxrs-spec@javaee.groups.io
Cc:
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client
Date: Wed, Dec 13, 2017 1:27 AM
 

Andy,

 

as much as I would love to work on JAX-RS 2.1.1, 2.2 or 3.0, actually this is impossible at the moment. The reason is that JAX-RS is to be migrated from Oracle to the Eclipse Foundation. At the moment, it is unclear under which conditions and in what timeframe a maintenance release of the JAX-RS Specification PDF could be published. Also at the moment, it is unclear if such a maintenance release would be standardized by the JCP, or by a different organization. I am sorry not to be able to give a better answer, but it is all in the hands of Oracle's lawyers and the PMC still.

 

I have CC'ed IBM's PMC member Kevin Suter. Maybe he has an updated schedule on this he is willing to share with you.

 

Regarding the question itself, the JAX-RS specification does not make any assumptions upon invoking users. In particular, a scenario where three users  / three threads share and extend one single "fiber" is not part of JAX-RS. Hence, the specification leaves this open intentionally but just says that context capture "has to work". Could you elaborate how such a scenario could look like, where three threads invoked by three different users have access to the same "fiber"?

 

-Markus

EG JSR 370

 

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Andy McCright
Sent: Dienstag, 12. Dezember 2017 23:44
To: jaxrs-spec@javaee.groups.io
Subject: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

Hi Experts,

 

While working on the JAX-RS 2.1 implementation in Liberty, a colleague of mine discovered some inconsistent behavior related to the reactive client's CompletionStage with regard to executors.  He wrote me:

 

 

When a ManagedExecutorService is used as the default asynchronous execution facility for a CompletionStage created by a JAX-RS client's CompletionStageRxInvoker, the specification is currently unclear as to exactly when thread context should be captured for propagation to the CompletionStage and its dependent stages.
The ambiguity similarly exists when ManagedExecutorService is explicitly specified in any of the *Async methods. For example, completionStage.thenRunAsync(runnable, executor).

In discussions within our team, we have come to the conclusion that it makes sense for thread context capture to always (and only) be done at the point in time where CompletionStageRxInvoker.<method> is invoked to create the CompletionStage and at each point where CompletionStage.*Async is invoked to create a dependent stage.

Let's consider a scenario where code running as user1 uses the JAX-RS client to create a CompletionStage, and a subsequent block of code running as user2 adds a dependent stage, followed by another block of code running as user3, which adds another dependent stage.
This could be shown as:

Code running as user1 invokes:  stage1 = clientBuilder.executorService(managedExecService).build().target(uri).request().rx().method(...);
Code running as user2 invokes:  stage2 = stage1.handleAsync(function2);
Code running as user3 invokes:  stage3 = stage2.handleAsync(function3);

With our proposal, the spec would guarantee that function2 always runs as user2 and function3 always runs as user3, which we believe to best match the intent of the user.  Note that, lacking this behavior as proposed, it seems wrong to allow user2 or user3 to be able to add dependent stages that run as user1. Therefore, we would not want thread context capture to be done at alternate points, such as at the end of the execution of the previous stage.  We would like to see the spec updated to state this guarantee about thread context capture and transfer when using the JAX-RS client builder with ManagedExecutorService, such that users will be able to rely on a predictable and useful behavior.

 

 

Would it be possible to clarify this in the spec - perhaps as part of a maintenance release?  If it would help, I could draft up some text and submit a pull request.

 

Thanks in advance for your review,

 

Andy



J. Andrew McCright
IBM WebSphere Development
+1 507 253 7448
TL 553-7448
andymc@...

 

 

 

 

 

 

Join jaxrs-spec@javaee.groups.io to automatically receive all group messages.