Skip to content

Conversation

@arjantijms
Copy link
Contributor

This solves the race condition - keep the effective injectionManager in a thread local. As multiple threads can modify the injectionManager and the InjectionManagerInjectedCdiTarget instances are global, effectiveInjectionManager must be scoped to the thread. It's actually scoped to a single WebTarget initialization and removed at the end of the initialization in the done() method of CdiComponentProvider

The problem:

A race condition happens when many threads execute REST client call at the same (more specifically, when WebTarget.request() is called.

Symptom:

Occasional
IllegalStateException: Could not find an implementation of ClassAnalyzer with name CdiInjecteeSkippingClassAnalyzer from WebTarget.request

Reason for the exception:

  • The injectionManager is set in the initialization phase, before it's used. It's stored to a shared volatile variable and later picked up
  • If some thread sets the shared volatile variable to another injectionManager, before the original thread uses it, the original thread would use another thread's injectionManager
  • In case the second thread doesn't bind the ClassAnalyzer class in time before the first thread uses it, the first thread won't have ClassAnalyzer bean available and throws exception

A reproducer is described in payara/Payara#7753.

The original fix in Payara fork (53ae843) addresses this by a workaround - a retry in case of exception, which works, because by the next time, the other thread has enough time to bind the ClassAnalyzer class. But that solution isn't efficient.

(resubmit after #6049)

Happens when many threads execute REST client call at the same.

Symptom:

Occasional 
IllegalStateException: Could not find an implementation of ClassAnalyzer with name CdiInjecteeSkippingClassAnalyzer
from WebTarget.request

Reason for the exception:
* The injectionManager is set earlier than it's used, it's stored to a shared volatile variable and later picked up
* If some thread sets the shared volatile variable to another injectionManager, the original thread would use another threads injectionManager
* In case the second thread doesn't bind the ClassAnalyzer class in time before the first thread uses it, the first thread won't have ClassAnalyzer bean available and throws exception
Remove the thread local from the correct component (same as retrieved in the CdiComponentProvider.initialize method)

Save a few nanoseconds by calling get instead of set on the thread local, log an error if a leaking injectionManager detected.
If ClientRuntime needs CDI beans, it initializes CdiComponentProvider again, we need to clean up later.
@arjantijms
Copy link
Contributor Author

(this was already approved in the original PR)

@OndroMih
Copy link

@arjantijms , isn't it better to reopen my PR and change the target branch?

@arjantijms arjantijms closed this Jan 14, 2026
@arjantijms
Copy link
Contributor Author

isn't it better to reopen my PR and change the target branch?

Yes, I just did that. Sorry for the noise.

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

Successfully merging this pull request may close these issues.

2 participants