[ISSUE]: Binding proxies to Fault Tolerance mechanism

49 views
Skip to first unread message

Buhake Sindi

unread,
Jun 13, 2025, 3:36:26 PMJun 13
to MicroProfile
Hi everyone,

Here's the dilemma that I believe we need to view.

Suppose you have an interface, SomeInterface, that generates a proxy through a factory and is now registered for CDI scoping and injection.

Now, suppose this SomeInterface has a @Retry Fault Tolerance mechanism applied to a method.

Currently, the Fault Tolerance interceptor (from any Reference Implementation of FT) won't trigger since it's not a CDI managed bean (concrete implementation). The proxy has no way of inheriting the @Retry annotation from the interface SomeInterface.

This is the same problem why RestClient cannot be applied with Fault Tolerance mechanism.

A solution is to use InterceptorFactory, as follows:

InterceptionFactory<T> factory = beanManager.createInterceptionFactory(creationalContext, aiServiceInterfaceClass); factory.configure().add(new InterceptorBindingLiteral()); instance = factory.createInterceptedInstance(instance); Now, this requires that you know the Interceptor binding annotation from your MP compatible Application server (whether it runs Helidon FT, SmallRye FT, Apache Safeguard, etc.).

Now, Quarkus have figured out a way to make this problem work, but for the rest, not so much.

I suggest that we introduce the getInterceptorBinding() method to the CDI `Bean` interface, e.g.,

public Set<Annotation> getInterceptorBindings() {

if (interceptorBindings == null)

interceptorBindings = new HashSet<>();

return interceptorBindings;

} And on the create() method, introduce the InterceptionFactory if the interceptor binding set is not empty. That way, each RI of FT can introduce its interceptor binding annotations to the said bean.

SmallRye: @FaultToleranceBinding
Helidon: @CommandBinding

Apache: @Safeguard

With this approach, it can propagate to RestClient as well.

Alternatively, try a use a service loader that provides a mean to register our bean, ready for interception.

Thoughts?

This comes from implementing Fault Tolerance to Langchain4J AI Services

Code: https://github.com/langchain4j/langchain4j-cdi/blob/main/langchain4j-cdi-fault-tolerance/src/main/java/dev/langchain4j/cdi/faulttolerance/spi/Langchain4JFaultToleranceExtension.java
The CDI Bean in question: https://github.com/langchain4j/langchain4j-cdi/blob/main/langchain4j-cdi-portable-ext/src/main/java/dev/langchain4j/cdi/core/portableextension/LangChain4JAIServiceBean.java

Thanks.

Ed Burns

unread,
Jun 13, 2025, 7:02:53 PMJun 13
to microp...@googlegroups.com
Thanks Buhake (boo ha kay) for picking up the slack. I had failed to report this.

Ed


From: microp...@googlegroups.com <microp...@googlegroups.com> on behalf of Buhake Sindi <buh...@gmail.com>
Sent: Friday, June 13, 2025 12:36:26 PM
To: MicroProfile <microp...@googlegroups.com>
Subject: [EXTERNAL] [microprofile] [ISSUE]: Binding proxies to Fault Tolerance mechanism
 
--
You received this message because you are subscribed to the Google Groups "MicroProfile" group.
To unsubscribe from this group and stop receiving emails from it, send an email to microprofile...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/microprofile/a971c0a8-e0dc-4c61-88e6-7e5a11c4c5f5n%40googlegroups.com.

Ladislav Thon

unread,
Jun 14, 2025, 4:13:21 AMJun 14
to MicroProfile
Hi,

Dne pá 13. 6. 2025 21:36 uživatel Buhake Sindi <buh...@gmail.com> napsal:
Hi everyone,

Here's the dilemma that I believe we need to view.

Suppose you have an interface, SomeInterface, that generates a proxy through a factory and is now registered for CDI scoping and injection.

How is it registered to become a CDI bean? Do you create a producer or a synthetic bean? I don't see any other way, so I suppose it's one of these.

Now, suppose this SomeInterface has a @Retry Fault Tolerance mechanism applied to a method.

Currently, the Fault Tolerance interceptor (from any Reference Implementation of FT) won't trigger since it's not a CDI managed bean (concrete implementation). The proxy has no way of inheriting the @Retry annotation from the interface SomeInterface.

This is the same problem why RestClient cannot be applied with Fault Tolerance mechanism.

Aside: it can and it is, though the actual means are not specified (which is fine IMHO).


A solution is to use InterceptorFactory, as follows:

InterceptionFactory<T> factory = beanManager.createInterceptionFactory(creationalContext, aiServiceInterfaceClass); factory.configure().add(new InterceptorBindingLiteral()); instance = factory.createInterceptedInstance(instance); Now, this requires that you know the Interceptor binding annotation from your MP compatible Application server (whether it runs Helidon FT, SmallRye FT, Apache Safeguard, etc.).

I'm lost here. Why do you need to know the implementation binding annotation? I believe the only correct way to do this is to inspect the interface and "copy" the relevant annotations to the factory (both on the class level and on the level of individual methods). Everything else is guesswork.

Now, Quarkus have figured out a way to make this problem work, but for the rest, not so much.

Aside: not sure what you mean here, but that's not relevant... :-)

I suggest that we introduce the getInterceptorBinding() method to the CDI `Bean` interface, e.g.,

public Set<Annotation> getInterceptorBindings() {

if (interceptorBindings == null)

interceptorBindings = new HashSet<>();

return interceptorBindings;

} And on the create() method, introduce the InterceptionFactory if the interceptor binding set is not empty.


If you want to suggest adding a feature to CDI, either file an issue in CDI or at least write an e-mail to the cdi-dev mailing list. But note that you will have to add a lot more details, because I (speaking with my CDI committer hat on) have absolutely no idea what you're proposing here.

That way, each RI of FT can introduce its interceptor binding annotations to the said bean.

SmallRye: @FaultToleranceBinding
Helidon: @CommandBinding

Apache: @Safeguard

With this approach, it can propagate to RestClient as well.

Alternatively, try a use a service loader that provides a mean to register our bean, ready for interception.

Thoughts?

This comes from implementing Fault Tolerance to Langchain4J AI Services

Code: https://github.com/langchain4j/langchain4j-cdi/blob/main/langchain4j-cdi-fault-tolerance/src/main/java/dev/langchain4j/cdi/faulttolerance/spi/Langchain4JFaultToleranceExtension.java
The CDI Bean in question: https://github.com/langchain4j/langchain4j-cdi/blob/main/langchain4j-cdi-portable-ext/src/main/java/dev/langchain4j/cdi/core/portableextension/LangChain4JAIServiceBean.java


Ah OK, so it's a synthetic bean indeed. I'm not sure why you're implementing the Bean interface directly, using the configurator approach is much easier and a lot less error-prone.

In any case, as I wrote above, you know the interface you're proxying and you have the InterceptionFactory. It's a simple matter of reflectively inspecting the interface and putting all relevant annotations you discover to the factory. I believe that's all you need. 

LT

Buhake Sindi

unread,
Jun 14, 2025, 5:29:41 AMJun 14
to microp...@googlegroups.com
Thanks Ladislav,

The problem is that some of these interception binding annotations are package private (ahem, Helidon). Bean implementation aside, the solution should, ideally, allow to be linked to any interceptor during bean registration.

Also, this solution does not work (as to my knowledge) when using Build Compatible Extension (introduced in CDI 4). 

It should be that developers shouldn't choose what type of FT RI they should use in their projects to enable FT if the app server runtime already supports it. By introducing such features in the spec, providers can register their interceptor bindings and this can be used for triggering InterceptionFactory.

Thanks,

Virus-free.www.avast.com

Ladislav Thon

unread,
Jun 14, 2025, 6:44:10 AMJun 14
to MicroProfile


Dne so 14. 6. 2025 11:29 uživatel Buhake Sindi <buh...@gmail.com> napsal:
Thanks Ladislav,

The problem is that some of these interception binding annotations are package private (ahem, Helidon). Bean implementation aside, the solution should, ideally, allow to be linked to any interceptor during bean registration.

Sorry, I still don't understand why you're focusing on there implementation details. I might be missing something, but what's wrong with scanning the interface for all the interceptor binding annotations you need (all the FT annotations are interceptor bindings) and copying them to the InterceptionFactory? That should work, no?

Also, this solution does not work (as to my knowledge) when using Build Compatible Extension (introduced in CDI 4). 

Yeah, CDI Lite currently doesn't have an equivalent of InterceptionFactory. We have a proprietary equivalent in Quarkus, which I honestly think is good enough even for this usecase (transfer the interface from build time to runtime and use it as a bindings source), but we didn't submit it to the spec yet. Perhaps we should.

BTW, your BuildCompatibleExtension loads Class objects from TCCL, which is a bad idea. I don't see anything forcing you to do that, ClassInfo objects should be good enough for everything you need (you can even transfer them from build time to runtime, they materialize as Class objects on the other side).


It should be that developers shouldn't choose what type of FT RI they should use in their projects to enable FT if the app server runtime already supports it. By introducing such features in the spec, providers can register their interceptor bindings and this can be used for triggering InterceptionFactory.

I agree and I don't see anything preventing you from doing that, at least in CDI Full. The only thing missing in CDI Lite is mentioned above. 

LT

Ladislav Thon

unread,
Jun 14, 2025, 8:02:20 AMJun 14
to MicroProfile


Dne so 14. 6. 2025 12:43 uživatel Ladislav Thon <lad...@gmail.com> napsal:


Dne so 14. 6. 2025 11:29 uživatel Buhake Sindi <buh...@gmail.com> napsal:
Thanks Ladislav,

The problem is that some of these interception binding annotations are package private (ahem, Helidon). Bean implementation aside, the solution should, ideally, allow to be linked to any interceptor during bean registration.

Sorry, I still don't understand why you're focusing on there implementation details. I might be missing something, but what's wrong with scanning the interface for all the interceptor binding annotations you need (all the FT annotations are interceptor bindings) and copying them to the InterceptionFactory? That should work, no?

Oh, I see why it doesn't necessarily have to work -- the interceptors themselves use a different interceptor binding and there's extra piece of integration code to bridge that gap.

I'm not sure at the moment if the integration code could be fixed, but that would be my preference. I'll take a look on the SmallRye Fault Tolerance side next week. 

LT

Buhake Sindi

unread,
Jun 14, 2025, 8:40:03 AMJun 14
to microp...@googlegroups.com
That's the exact problem. Sorry if I didn't communicate it properly earlier.

Virus-free.www.avast.com

You received this message because you are subscribed to a topic in the Google Groups "MicroProfile" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/microprofile/lto5IHWkN1A/unsubscribe.
To unsubscribe from this group and all its topics, send an email to microprofile...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/microprofile/CALbocO%3DPwNWg%3DRwrn4E1-EpAPwHm%2B_JJY2jTtwhek05oRpGnUg%40mail.gmail.com.

Buhake Sindi

unread,
Jun 24, 2025, 5:30:35 PMJun 24
to MicroProfile
Hi everyone,

I believe this discussion can be tabled with the Jakarta EE CDI team, correct?

Thanks.

Emily Jiang

unread,
Sep 12, 2025, 11:08:57 AM (6 days ago) Sep 12
to MicroProfile
Hi LT,
Any update on this?
Thanks
Emily

Ladislav Thon

unread,
Sep 12, 2025, 1:13:48 PM (6 days ago) Sep 12
to microp...@googlegroups.com
We talked about this on a CDI call in early July (see https://docs.google.com/document/d/1LJgN9UZlSwYASnE-IpaFVw9D7spJoK2J1vlys7AyNG4/edit?tab=t.0#heading=h.74qjpme4qui0). There's also this issue: https://github.com/jakartaee/cdi/issues/873 My personal opinion is we should allow interceptors to say "I only need at least one binding annotation to be present, not all of them" (e.g. by adding an annotation on the interceptor class). Then, MP FT implementations wouldn't have to create an intermediate binding and things would work out of the box.

LT

pá 12. 9. 2025 v 17:09 odesílatel 'Emily Jiang' via MicroProfile <microp...@googlegroups.com> napsal:
Reply all
Reply to author
Forward
0 new messages