fix: defer CDI request context destruction for streaming requests by kabir · Pull Request #904 · a2aproject/a2a-java · GitHub
Skip to content

fix: defer CDI request context destruction for streaming requests - #904

Merged
kabir merged 3 commits into
a2aproject:mainfrom
kabir:issues_893
Jun 1, 2026
Merged

kabir merged 3 commits into
a2aproject:mainfrom
kabir:issues_893

Conversation

@kabir

@kabir kabir commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Streaming (SSE) requests dispatch agent work to a background thread via ManagedExecutor and return immediately. The existing runInRequestContext() terminates the CDI request context in a finally block, destroying all @RequestScoped beans before the agent thread runs. This causes ContextNotActiveException when the agent accesses request-scoped beans (e.g. OIDC token propagation via @accesstoken).

Add runInRequestContextDeferred() which deactivates the context (detaching it from the worker thread) but defers bean destruction to the HTTP response lifecycle via endHandler/closeHandler. This keeps all @RequestScoped beans alive for the duration of the streaming response.

  • JSONRPC routes: use runInRequestContextDeferred for the main handler (handles both streaming and non-streaming)
  • REST routes: add authenticatedStreaming() wrapper for message:stream and tasks/:subscribe endpoints
  • Apply same changes to compat-0.3 JSONRPC and REST routes
  • Add streaming variant of CDI propagation test

Fixes #893 🦕

Streaming (SSE) requests dispatch agent work to a background thread via
ManagedExecutor and return immediately. The existing runInRequestContext()
terminates the CDI request context in a finally block, destroying all
@RequestScoped beans before the agent thread runs. This causes
ContextNotActiveException when the agent accesses request-scoped beans
(e.g. OIDC token propagation via @accesstoken).

Add runInRequestContextDeferred() which deactivates the context (detaching
it from the worker thread) but defers bean destruction to the HTTP response
lifecycle via endHandler/closeHandler. This keeps all @RequestScoped beans
alive for the duration of the streaming response.

- JSONRPC routes: use runInRequestContextDeferred for the main handler
  (handles both streaming and non-streaming)
- REST routes: add authenticatedStreaming() wrapper for message:stream
  and tasks/:subscribe endpoints
- Apply same changes to compat-0.3 JSONRPC and REST routes
- Add streaming variant of CDI propagation test

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a deferred CDI request context mechanism (runInRequestContextDeferred) in VertxSecurityHelper to support streaming (SSE) requests where background threads need access to request-scoped beans. This mechanism is integrated into JSON-RPC and REST routing classes via the new authenticatedStreaming handler, and integration tests have been added to verify this behavior. The review feedback suggests catching Throwable instead of Exception in runInRequestContextDeferred to ensure the context is safely cleaned up even if an Error occurs.

@ehsavoie ehsavoie left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @kabir

@kabir
kabir merged commit dbe8f25 into a2aproject:main Jun 1, 2026
11 of 12 checks passed
salaboy pushed a commit to salaboy/a2a-java that referenced this pull request Jun 19, 2026
…aproject#904)

* fix: defer CDI request context destruction for streaming requests

Streaming (SSE) requests dispatch agent work to a background thread via
ManagedExecutor and return immediately. The existing runInRequestContext()
terminates the CDI request context in a finally block, destroying all
@RequestScoped beans before the agent thread runs. This causes
ContextNotActiveException when the agent accesses request-scoped beans
(e.g. OIDC token propagation via @accesstoken).

Add runInRequestContextDeferred() which deactivates the context (detaching
it from the worker thread) but defers bean destruction to the HTTP response
lifecycle via endHandler/closeHandler. This keeps all @RequestScoped beans
alive for the duration of the streaming response.

- JSONRPC routes: use runInRequestContextDeferred for the main handler
  (handles both streaming and non-streaming)
- REST routes: add authenticatedStreaming() wrapper for message:stream
  and tasks/:subscribe endpoints
- Apply same changes to compat-0.3 JSONRPC and REST routes
- Add streaming variant of CDI propagation test
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.

RequestScoped context was not active when trying to obtain a bean instance for a client proxy of PRODUCER_METHOD ....D bean

2 participants