Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@Asynchronous doesn't belong in org.eclipse.microprofile.faulttolerance #415

Open
gavinking opened this issue Feb 22, 2019 · 10 comments
Open

Comments

@gavinking
Copy link
Member

gavinking commented Feb 22, 2019

The notion of an @Asynchronous method is one that's existed in Java EE since it was introduced in EJB 3.1. It was arguably a mistake at the time to have put this annotation in the javax.ejb package, instead of allowing it to have been used with any CDI bean, but the history was that at the time CDI was a under a cloud of controversy and trying to present as small a target as possible, and was therefore trying not to step on EJB's toes too much.

So the addition of org.eclipse.microprofile.faulttolerance.Asynchronous which can, as I understand it, be used on any CDI bean is a big improvement from this point of view. Now, if I'm not misunderstanding, we can add asynchronous methods to any CDI bean. Excellent, if true!

However, from what I can tell from a cursory inspection of its documented semantics, @Asynchronous doesn't have anything much in the way of semantics that are specific to Fault Tolerance. That makes sense: asynchronicity and fault tolerance are relatively orthogonal concerns, though I can see how there are some semantics that need to be well-defined at their intersection.

Nevertheless, asynchronicity isn't an aspect of Fault Tolerance, and therefore it doesn't seem to me that @Asynchronous belongs in the org.eclipse.microprofile.faulttolerance package. I'm not sure where it does belong, but ... not there.

Hrrrrm, perhaps a better place for it to live would be in org.eclipse.microprofile.concurrent, since it seems much more closely related to the functionality in that package? I'm not sure.

@Emily-Jiang
Copy link
Member

Thank you @gavinking for your thoughts! Inventing @Asynchronous was originally triggered to specify a multithreading mode of bulkhead. As per your comments, since there is no such asynchronous api, we have to introduce it first. This annotation is quite useful. I like what you suggested though. Maybe it is better to be moved under concurrency spec. When the concurrency spec is released, we can interlock more to see whether we can make that move.

@gavinking
Copy link
Member Author

@Emily-Jiang yep, great. Indeed, I hope the Concurrency spec will define a relationship between @Asynchronous and ManagedExecutors, which would make the connection even clearer.

@cescoffier
Copy link

I agree with @gavinking that @Asynchronous does not belong in fault tolerance.

There are many MicroProfile specifications (fault tolerance, rest client...) making assumptions on the execution model (JavaEE execution model). However, this is a blocker for anything reactive and non-blocking as the threading model is very different (avoid thread pools, reuse the threads to handle concurrent requests). So almost all spec will need to be updated if MP wants to embrace reactive.

@manovotn
Copy link
Contributor

manovotn commented Mar 5, 2019

+1 for this, @Asynchronous seems misplaced.
Furthermore it shouldn't explicitly speak about running things on different thread as asynchronous can but doesn't need to be on another thread. Therefore a re-wording of the annotation would be appropriate as well. We can say that the task will be performed in async manner (same or different thread) with MP Conc context propagation in place.

Just note that this also means the annotation will entail perf overhead of MP Conc propagation.

@kenfinnigan
Copy link
Contributor

+1 to removing @Asynchronous from the spec.

@Azquelt
Copy link
Member

Azquelt commented Mar 5, 2019

I'd agree with removing @Asynchronous, but I'd want to make sure we have covered all of the use cases which @Asynchronous currently allows.

Off the top of my head, these are the additional things you can do with @Asynchronous and Fault Tolerance which you can't currently do without it:

  • Have a Bulkhead where tasks are queued
  • Have a Timeout where a result is returned when the timeout expires, even if the operation being run isn't interruptible
  • Apply Fault Tolerance logic around the completion of a CompletionStage (as opposed to applying it around a method execution)

One option might be to have an API that allows the user to wrap a MP concurrency executor to produce a new executor which applies Fault Tolerance policies.

@kenfinnigan
Copy link
Contributor

I might be missing something, as I've not been involved except tangentially with this spec so far, but shouldn't what you describe occur irrespective of an @Asynchronous being present?

If it doesn't, maybe the spec needs some work to reflect it's not tied to it

@manovotn
Copy link
Contributor

manovotn commented Mar 5, 2019

@kenfinnigan Bulkhead seems to have hard-wired thread mentions into its javadoc. I saw no similar mention in Timeout.
Spec itself hardcodes the "different thread" approach again for any usage of @Asynchronous with other MP FT annotation, see this.
So I would say spec indirectly implies that without async annotation, you are bound to do everything synchronously which is unfortunate.

I think what @Azquelt meant was what it implies if you were running async which isn't the default case it seems.
Then again, I am MP FT greenhorn, so might be missing some bits here...

@Azquelt
Copy link
Member

Azquelt commented Mar 5, 2019

I guess there's two questions, "what does the spec say", and "why does it say what it does". I'll try to answer the second question to the best of my knowledge.

Everything not annotated with @Asynchronous should run synchronously. The user needs to make additional considerations if their code is going to run asynchronously so we should be careful not to surprise them.

If we're using @Timeout and running synchronously then there's no way to return early, other than to have whatever code is running respond to the thread being interrupted. Unfortunately, not all long running operations do this.

If you want to apply fault tolerance policies around a CompletionStage, then presumably you've got that CompletionStage from another asynchronous API (e.g. MP Concurrency or JAX-RS client). In theory, there's no need to require @Asynchronous here, but we chose to for two reasons:

  1. When you run the first time, you can make a synchronous call (which runs quickly and just calls some other async API and passes back the CompletionStage) but if the CompletionStage results in a failure, you may need to retry and call the method again but at this point you're on a different thread. In a JavaEE type execution model, that can make a big difference, e.g. the request context could have ended or the original call may have been in a transaction.
    We wanted to avoid the case where the initial call might execute one way but any retries execute in a different way as that raises the possibility that it might work if it succeeds first time but doesn't work if it needs to retry, which might not be picked up in testing.
  2. Fault Tolerance annotations are applied to methods and in most cases, the fault tolerance policy is applied only around the method call itself, if the method returns a result the the fault tolerance processing is finished. To get this behaviour on CompletionStage, we need to change that. Even if the method returns a CompletionStage, we don't apply fault tolerance processing until the CompletionStage actually completes.
    If you're not familiar with it, this seems a bit weird, so we decided on restrict this behaviour to when CompletionStage is used with @Asynchronous (at which point, you're expecting weirdness anyway).

The decision to make Bulkhead behave differently was taken before I was involved in the project, so I'm not sure what the rationale there was.

@gavinking
Copy link
Member Author

gavinking commented Mar 5, 2019

Off the top of my head, these are the additional things you can do with @Asynchronous and Fault Tolerance which you can't currently do without it:

[snip]

Right, but it seems to me that these should be additional semantics that Fault Tolerance adds to an @Asynchronous method when that functionality is explicitly specified by the user. I would not have thought that it would be stuff that you just get implicitly whenever you declare that a method is @Asynchronous.

That is, I could have an @Asynchronous method that isn't fault tolerant, but then when the user starts enabling fault tolerance for that method, they would get that additional semantics without any change to the calling convention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants