Topics

Clarification regarding ManagedExecutorService in Rx Client


Andy McCright
 

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@...


 

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@...

 


Andy McCright
 

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@...

 

 

 


 

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@...

 

 

 

 


Andy McCright
 

Hi Markus,
 
Kevin is not subscribed to the JAX-RS mailing list (but if the conversation continues, he said he would be willing to join).  He sent this message:
 
Markus,
Unfortunately, I don't have any additional details on when the spec process will be finalized by the Eclipse efforts.  This is an area that we need to have some type of process put in place soon.  Maybe we need an interim solution until the final one is determined...  It's being discussed, but no answers to share at this point.

Concerning this type of technical, spec discussion...  Regardless of the move to Eclipse, updating a spec (even a clarification) post Java EE release is difficult.  What I would suggest is to continue having the technical discussion.  If a clarification is required, log a github Issue with the jax-rs github repo.  If this discussion highlights an issue with the current jax-rs TCK, then that should be a separate Issue.  For example, if existing tests are affected by this ambiguity, then these need to be identified as "excluded" for compliance testing.

By logging the Issue, at least all of us have something to point at if a customer situation would arise.  The Issue should document the expected interpretation as it is currently written.  If it's truly an "implementation detail", then we need to specify that.

When the spec process is figured out for EE4J, then these Issues can be examined and processed for inclusion in the next rev of the spec.

---------------------------------------------------
Kevin Sutter 
STSM, MicroProfile and Java EE architect

 
 
I'll reply in a separate email to the technical questions you raised.
 
Thanks, 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@...

 

 

 

 

 

 


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@...

 

 

 

 

 

 


 

Andy,

 

JAX-RS has technically no chance within Java EE 8 / Java SE 8 to enforce what you want. So it maks no sense to write anything like that into a maintenance release of that spec. What we could do in a future major or minor release (but not in a maintenance release) is to say that if some kind of "higher level control" (like the spec you mentioned) is part of Java SE or part of Java EE, that technology MUST be used, and describe the particular way how to apply it. But as that spec does not exists yet, we cannot discuss yet. Maybe I missed a point where JAX-RS 2.1.1 actually MUST enforce something (that's the only reason to produce a maintenance release of the spec) and that actually CAN technically get enforced (otherwise it makes no sense to mandate it), then please tell me the technical solution you want JAX-RS 2.1.1 to mandate.

 

BTW, this has nothing to do with Managed Executors at all. You have the very same question once you use the same scenario with any explicitly provided other Executor, too.

 

Thanks

-Markus

 

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

 

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@...

 

 

 

 

 

 

 


Ondrej Mihályi
 

I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

There's certainly a gap not covered by JAX-RS, CopletionStage API or any other Java SE or EE spec. The concurrency spec just says that managed executors preserve the context of the component that submits the task. But with CompletionStage, it's not clear what component actually submits the task. CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

I'm not sure whether specifying that a stage should store the current context and delegate it do async tasks is the best solution. It would be a breaking change and I still there's an equally important case for not delegating the current context (e.g. when a component only wants to build a pipeline which should all be executed in a different context).

I agree with Marcus that this doesn't belong to JAX-RS at all, it's only by coincidence a spec to use ComnpletionStage. I believe the same applies to async CDI events, which also return CompletionStage.

The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

@Resource
ContextService contextService;

@EJB
EJB1 ejb1;

public void someMethod(CompletionStage) {  
    Map<String, String> execProperties = new HashMap<>();
    execProperties.put("delegate.context", "true");
    EJB1 ejb1Proxy = contextService.createContextualProxy(ejb1, execProperties, EJB1.class);
    ejb1Proxy.syncMethod(stage);   // the proxy would modify the context to force that the CompletionStage delegates the current context
}

The above code expects that EJB1 is an interface but this could be work around with a helper class. Ideally, contextService would provide an alternative method to create a contextualProxy from a lambda expression to proxy only a single method call not a whole object.

-Ondro


2017-12-14 16:22 GMT+01:00 Andy McCright <andymc@...>:

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@...

 

 

 

 

 

 



 

Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

I think a good solution for the future would be that the Conccurency Utils API is extended so it provides a ManagedCompletableFuture. That new class could capture the thread each time a new stage is added. JAX-RS 2.2.1 could be "fixed" by saying that it was always assumed that way but for clarity it now MUST work that way. While technically this breaks existing code, it does that in the same way as ANY bug fix would do. So I think if there is a majority voting for such a change, we can do that. In the end it makes things more correct.

 

So next steps are, according to EE4J's new "code first" strategy:

 

* Filing issues with Github for Concurrency Utils API + TCK

* Same for JAX-RS

* Asking PMC for "more eagerly" setting up an initial team for Concurrency Utils and ask them to fix that.

* If someone is willing to contribute the changes, notify that team.

* When Concurrency Utils support that, THEN file an issue with JAX-RS API + TCK

 

Agreed? :-)

 

-Markus

 

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Ondrej Mihályi
Sent: Donnerstag, 14. Dezember 2017 18:58
To: jaxrs-spec@javaee.groups.io
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

There's certainly a gap not covered by JAX-RS, CopletionStage API or any other Java SE or EE spec. The concurrency spec just says that managed executors preserve the context of the component that submits the task. But with CompletionStage, it's not clear what component actually submits the task. CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

I'm not sure whether specifying that a stage should store the current context and delegate it do async tasks is the best solution. It would be a breaking change and I still there's an equally important case for not delegating the current context (e.g. when a component only wants to build a pipeline which should all be executed in a different context).

I agree with Marcus that this doesn't belong to JAX-RS at all, it's only by coincidence a spec to use ComnpletionStage. I believe the same applies to async CDI events, which also return CompletionStage.

The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

@Resource

ContextService contextService;

@EJB

EJB1 ejb1;

 

public void someMethod(CompletionStage) {  

    Map<String, String> execProperties = new HashMap<>();

    execProperties.put("delegate.context", "true");

    EJB1 ejb1Proxy = contextService.createContextualProxy(ejb1, execProperties, EJB1.class);

    ejb1Proxy.syncMethod(stage);   // the proxy would modify the context to force that the CompletionStage delegates the current context

}

 

The above code expects that EJB1 is an interface but this could be work around with a helper class. Ideally, contextService would provide an alternative method to create a contextualProxy from a lambda expression to proxy only a single method call not a whole object.

 

-Ondro

 

 

2017-12-14 16:22 GMT+01:00 Andy McCright <andymc@...>:

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@...

 

 

 

 

 

 

 

 


Andy McCright
 

Hi Markus, Ondro
 
Sorry for the slow reply - was out sick yesterday.  I think your proposed plan is a good course of action.  
 
Some additional thoughts:
 
MK> Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.
 
 
I also cannot speak for the RI, but using CXF we return a CompleteableFuture, and the behavior is more like what Ondro stated - that the context of the last completed stage gets propagated to the next stage.  This might be ok in Java SE environments, but obviously is not good in Java EE (where transaction, security, metadata, naming, etc. contexts are essential).
 
OM> I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.
 
Do you have a link that describes that behavior?  It does seem consistent with the behavior we are seeing with CXF (which uses a CompleteableFuture), but in the javadoc [1] for CompletionStage, it seems like the behavior is defined by the implementing class (I may be misinterpreting the text, so if you've got a link that makes it more clear, that would really help me) :
  • Dependencies among stages control the triggering of computations, but do not otherwise guarantee any particular ordering. Additionally, execution of a new stage's computations may be arranged in any of three ways: default execution, default asynchronous execution (using methods with suffix async that employ the stage's default asynchronous execution facility), or custom (via a supplied Executor). The execution properties of default and async modes are specified by CompletionStage implementations, not this interface. Methods with explicit Executor arguments may have arbitrary execution properties, and might not even support concurrent execution, but are arranged for processing in a way that accommodates asynchrony.
 
OM> CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.
 
We are seeing inconsistent results where sometimes the servlet's context is used and sometimes the most-recently completed stage's context (which in our tests have no context because we executed that stage with a non-managed executor) depending on the timing and which stages complete faster.
 
OM> The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:
  
I like this idea, but my preference would be for the default to be the stage caller's context, but that it would be possible to use a different context via the ContextService.  That way, if the EJB has different contexts, when it calls stage.runAsync(task, managedES) that task would run with the EJB's context _unless_ the EJB was invoked via the ContextService's proxy that specified to use the Servlet's context.  In any case, I agree that this conversation is more suited for the Concurrency spec than JAX-RS.
 
Thanks for the feedback guys!  I appreciate it.  I'll discuss with Nathan (my colleague who is on the Concurrency EG) and start the process that Markus outlined - opening an issue.  I'll also check with Kevin Sutter about trying to expedite the Concurrency spec to the Eclipse Foundation.
 
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: Fri, Dec 15, 2017 1:04 AM
 

Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

I think a good solution for the future would be that the Conccurency Utils API is extended so it provides a ManagedCompletableFuture. That new class could capture the thread each time a new stage is added. JAX-RS 2.2.1 could be "fixed" by saying that it was always assumed that way but for clarity it now MUST work that way. While technically this breaks existing code, it does that in the same way as ANY bug fix would do. So I think if there is a majority voting for such a change, we can do that. In the end it makes things more correct.

 

So next steps are, according to EE4J's new "code first" strategy:

 

* Filing issues with Github for Concurrency Utils API + TCK

* Same for JAX-RS

* Asking PMC for "more eagerly" setting up an initial team for Concurrency Utils and ask them to fix that.

* If someone is willing to contribute the changes, notify that team.

* When Concurrency Utils support that, THEN file an issue with JAX-RS API + TCK

 

Agreed? :-)

 

-Markus

 

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Ondrej Mihályi
Sent: Donnerstag, 14. Dezember 2017 18:58
To: jaxrs-spec@javaee.groups.io
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

There's certainly a gap not covered by JAX-RS, CopletionStage API or any other Java SE or EE spec. The concurrency spec just says that managed executors preserve the context of the component that submits the task. But with CompletionStage, it's not clear what component actually submits the task. CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

I'm not sure whether specifying that a stage should store the current context and delegate it do async tasks is the best solution. It would be a breaking change and I still there's an equally important case for not delegating the current context (e.g. when a component only wants to build a pipeline which should all be executed in a different context).

I agree with Marcus that this doesn't belong to JAX-RS at all, it's only by coincidence a spec to use ComnpletionStage. I believe the same applies to async CDI events, which also return CompletionStage.

The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

@Resource

ContextService contextService;

@EJB

EJB1 ejb1;

 

public void someMethod(CompletionStage) {  

    Map<String, String> execProperties = new HashMap<>();

    execProperties.put("delegate.context", "true");

    EJB1 ejb1Proxy = contextService.createContextualProxy(ejb1, execProperties, EJB1.class);

    ejb1Proxy.syncMethod(stage);   // the proxy would modify the context to force that the CompletionStage delegates the current context

}

 

The above code expects that EJB1 is an interface but this could be work around with a helper class. Ideally, contextService would provide an alternative method to create a contextualProxy from a lambda expression to proxy only a single method call not a whole object.

 

-Ondro

 

 

2017-12-14 16:22 GMT+01:00 Andy McCright <andymc@...>:

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@...

 

 

 

 

 

 

 

 

 

 


 

Good luck. Please keep us informed.

-Markus

 

 

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

 

Hi Markus, Ondro

 

Sorry for the slow reply - was out sick yesterday.  I think your proposed plan is a good course of action.  

 

Some additional thoughts:

 

MK> Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

 

I also cannot speak for the RI, but using CXF we return a CompleteableFuture, and the behavior is more like what Ondro stated - that the context of the last completed stage gets propagated to the next stage.  This might be ok in Java SE environments, but obviously is not good in Java EE (where transaction, security, metadata, naming, etc. contexts are essential).

 

OM> I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

Do you have a link that describes that behavior?  It does seem consistent with the behavior we are seeing with CXF (which uses a CompleteableFuture), but in the javadoc [1] for CompletionStage, it seems like the behavior is defined by the implementing class (I may be misinterpreting the text, so if you've got a link that makes it more clear, that would really help me) :

  • Dependencies among stages control the triggering of computations, but do not otherwise guarantee any particular ordering. Additionally, execution of a new stage's computations may be arranged in any of three ways: default execution, default asynchronous execution (using methods with suffix async that employ the stage's default asynchronous execution facility), or custom (via a supplied Executor). The execution properties of default and async modes are specified by CompletionStage implementations, not this interface. Methods with explicit Executor arguments may have arbitrary execution properties, and might not even support concurrent execution, but are arranged for processing in a way that accommodates asynchrony.

 

OM> CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

We are seeing inconsistent results where sometimes the servlet's context is used and sometimes the most-recently completed stage's context (which in our tests have no context because we executed that stage with a non-managed executor) depending on the timing and which stages complete faster.

 

OM> The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

  

I like this idea, but my preference would be for the default to be the stage caller's context, but that it would be possible to use a different context via the ContextService.  That way, if the EJB has different contexts, when it calls stage.runAsync(task, managedES) that task would run with the EJB's context _unless_ the EJB was invoked via the ContextService's proxy that specified to use the Servlet's context.  In any case, I agree that this conversation is more suited for the Concurrency spec than JAX-RS.

 

Thanks for the feedback guys!  I appreciate it.  I'll discuss with Nathan (my colleague who is on the Concurrency EG) and start the process that Markus outlined - opening an issue.  I'll also check with Kevin Sutter about trying to expedite the Concurrency spec to the Eclipse Foundation.

 

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: Fri, Dec 15, 2017 1:04 AM
 

Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

I think a good solution for the future would be that the Conccurency Utils API is extended so it provides a ManagedCompletableFuture. That new class could capture the thread each time a new stage is added. JAX-RS 2.2.1 could be "fixed" by saying that it was always assumed that way but for clarity it now MUST work that way. While technically this breaks existing code, it does that in the same way as ANY bug fix would do. So I think if there is a majority voting for such a change, we can do that. In the end it makes things more correct.

 

So next steps are, according to EE4J's new "code first" strategy:

 

* Filing issues with Github for Concurrency Utils API + TCK

* Same for JAX-RS

* Asking PMC for "more eagerly" setting up an initial team for Concurrency Utils and ask them to fix that.

* If someone is willing to contribute the changes, notify that team.

* When Concurrency Utils support that, THEN file an issue with JAX-RS API + TCK

 

Agreed? :-)

 

-Markus

 

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Ondrej Mihályi
Sent: Donnerstag, 14. Dezember 2017 18:58
To: jaxrs-spec@javaee.groups.io
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

There's certainly a gap not covered by JAX-RS, CopletionStage API or any other Java SE or EE spec. The concurrency spec just says that managed executors preserve the context of the component that submits the task. But with CompletionStage, it's not clear what component actually submits the task. CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

I'm not sure whether specifying that a stage should store the current context and delegate it do async tasks is the best solution. It would be a breaking change and I still there's an equally important case for not delegating the current context (e.g. when a component only wants to build a pipeline which should all be executed in a different context).

I agree with Marcus that this doesn't belong to JAX-RS at all, it's only by coincidence a spec to use ComnpletionStage. I believe the same applies to async CDI events, which also return CompletionStage.

The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

@Resource

ContextService contextService;

@EJB

EJB1 ejb1;

 

public void someMethod(CompletionStage) {  

    Map<String, String> execProperties = new HashMap<>();

    execProperties.put("delegate.context", "true");

    EJB1 ejb1Proxy = contextService.createContextualProxy(ejb1, execProperties, EJB1.class);

    ejb1Proxy.syncMethod(stage);   // the proxy would modify the context to force that the CompletionStage delegates the current context

}

 

The above code expects that EJB1 is an interface but this could be work around with a helper class. Ideally, contextService would provide an alternative method to create a contextualProxy from a lambda expression to proxy only a single method call not a whole object.

 

-Ondro

 

 

2017-12-14 16:22 GMT+01:00 Andy McCright <andymc@...>:

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@...

 

 

 

 

 

 

 

 

 

 

 


Andy McCright
 

Hi Guys,
 
Nathan has raised Issue #40 [1] with the Concurrency Spec to track this issue.  
 
Thanks again for the feedback,
 
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: Sat, Dec 16, 2017 11:24 AM
 

Good luck. Please keep us informed.

-Markus

 

 

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

 

Hi Markus, Ondro

 

Sorry for the slow reply - was out sick yesterday.  I think your proposed plan is a good course of action.  

 

Some additional thoughts:

 

MK> Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

 

I also cannot speak for the RI, but using CXF we return a CompleteableFuture, and the behavior is more like what Ondro stated - that the context of the last completed stage gets propagated to the next stage.  This might be ok in Java SE environments, but obviously is not good in Java EE (where transaction, security, metadata, naming, etc. contexts are essential).

 

OM> I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

Do you have a link that describes that behavior?  It does seem consistent with the behavior we are seeing with CXF (which uses a CompleteableFuture), but in the javadoc [1] for CompletionStage, it seems like the behavior is defined by the implementing class (I may be misinterpreting the text, so if you've got a link that makes it more clear, that would really help me) :

  • Dependencies among stages control the triggering of computations, but do not otherwise guarantee any particular ordering. Additionally, execution of a new stage's computations may be arranged in any of three ways: default execution, default asynchronous execution (using methods with suffix async that employ the stage's default asynchronous execution facility), or custom (via a supplied Executor). The execution properties of default and async modes are specified by CompletionStage implementations, not this interface. Methods with explicit Executor arguments may have arbitrary execution properties, and might not even support concurrent execution, but are arranged for processing in a way that accommodates asynchrony.

 

OM> CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

We are seeing inconsistent results where sometimes the servlet's context is used and sometimes the most-recently completed stage's context (which in our tests have no context because we executed that stage with a non-managed executor) depending on the timing and which stages complete faster.

 

OM> The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

  

I like this idea, but my preference would be for the default to be the stage caller's context, but that it would be possible to use a different context via the ContextService.  That way, if the EJB has different contexts, when it calls stage.runAsync(task, managedES) that task would run with the EJB's context _unless_ the EJB was invoked via the ContextService's proxy that specified to use the Servlet's context.  In any case, I agree that this conversation is more suited for the Concurrency spec than JAX-RS.

 

Thanks for the feedback guys!  I appreciate it.  I'll discuss with Nathan (my colleague who is on the Concurrency EG) and start the process that Markus outlined - opening an issue.  I'll also check with Kevin Sutter about trying to expedite the Concurrency spec to the Eclipse Foundation.

 

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: Fri, Dec 15, 2017 1:04 AM
 

Without any changes of the JAX-RS spec and Concurrency Utils spec JAX-RS will definitively capture the initial context only, so this is what is to be implemented right now. In any doubt please check the source code of the reference implementation. I have not done so, but I assume it currently will not capture thread contect at any later stage addition.

 

I think a good solution for the future would be that the Conccurency Utils API is extended so it provides a ManagedCompletableFuture. That new class could capture the thread each time a new stage is added. JAX-RS 2.2.1 could be "fixed" by saying that it was always assumed that way but for clarity it now MUST work that way. While technically this breaks existing code, it does that in the same way as ANY bug fix would do. So I think if there is a majority voting for such a change, we can do that. In the end it makes things more correct.

 

So next steps are, according to EE4J's new "code first" strategy:

 

* Filing issues with Github for Concurrency Utils API + TCK

* Same for JAX-RS

* Asking PMC for "more eagerly" setting up an initial team for Concurrency Utils and ask them to fix that.

* If someone is willing to contribute the changes, notify that team.

* When Concurrency Utils support that, THEN file an issue with JAX-RS API + TCK

 

Agreed? :-)

 

-Markus

 

 

From: jaxrs-spec@javaee.groups.io [mailto:jaxrs-spec@javaee.groups.io] On Behalf Of Ondrej Mihályi
Sent: Donnerstag, 14. Dezember 2017 18:58
To: jaxrs-spec@javaee.groups.io
Subject: Re: [jaxrs] Clarification regarding ManagedExecutorService in Rx Client

 

I also understand that, according to the current specs, the CompletionStage executes async tasks with the context of the previously finished task and not with the context of the component that calls async methods. In your example, Andy, the async tasks would be executed in the servlet's context.

 

There's certainly a gap not covered by JAX-RS, CopletionStage API or any other Java SE or EE spec. The concurrency spec just says that managed executors preserve the context of the component that submits the task. But with CompletionStage, it's not clear what component actually submits the task. CompletionStage only delegates a task submitted by "async" methods to the thread that finishes the previous CompletionStage task. Therefore, technically, CompletionStage cascades the context of the component that completed the initial CompletionStage/CompletableFuture. Since JAX-RS doesn't specify this and Concurrency utils don't mention CompletionStage at all, I believe this is the current behavior according to the spec. In your example, since the stage is created in a servlet, the servlet's context should propagate to all async executions in the stage.

 

I'm not sure whether specifying that a stage should store the current context and delegate it do async tasks is the best solution. It would be a breaking change and I still there's an equally important case for not delegating the current context (e.g. when a component only wants to build a pipeline which should all be executed in a different context).

I agree with Marcus that this doesn't belong to JAX-RS at all, it's only by coincidence a spec to use ComnpletionStage. I believe the same applies to async CDI events, which also return CompletionStage.

The best solution I see now is to update Concurrency Utils to enable to turn on the behavior of delegating the current context by CompletionStage. It could be reused also by future asynch constructs other than CompletionStage (e.g. Java 9 Flow) and also by third-party reactive providers supported by JAX-RS. One way to support it is to specify a standard execution property with the current ContextService API:

@Resource

ContextService contextService;

@EJB

EJB1 ejb1;

 

public void someMethod(CompletionStage) {  

    Map<String, String> execProperties = new HashMap<>();

    execProperties.put("delegate.context", "true");

    EJB1 ejb1Proxy = contextService.createContextualProxy(ejb1, execProperties, EJB1.class);

    ejb1Proxy.syncMethod(stage);   // the proxy would modify the context to force that the CompletionStage delegates the current context

}

 

The above code expects that EJB1 is an interface but this could be work around with a helper class. Ideally, contextService would provide an alternative method to create a contextualProxy from a lambda expression to proxy only a single method call not a whole object.

 

-Ondro

 

 

2017-12-14 16:22 GMT+01:00 Andy McCright <andymc@...>:

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@...