[Bug]: Blocking message/send loses the final event when the agent emits an event before completing

Fermée
#1,226 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@jeroenbellen y travaille déjà.

Depuis le 15/10/2026.

  • #1227 par @jeroenbellen — ouverte

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
35/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
java
Domaine
backend

Piste de recherche

Start in MainQueue's distributeToChildren, where the child.isClosed() skip drops the final event, and read how ChildQueue tracks isAwaitingFinalEvent() alongside MainEventBusProcessor and EventConsumer's polling loop. Reproduce with a DefaultRequestHandlerTest case that blocks the WORKING event until the handler closes the queue. Done when the blocking message/send returns the completed task promptly and the server-common tests pass.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

What happened?

Since 1.4.0.Final, a blocking message/send (returnImmediately false) to an agent that emits an event
before its terminal one, for example startWork() followed by complete(), returns about 3 seconds late.
With the timeouts of DefaultRequestHandler.builder() (2 s consumption timeout) it fails instead with
"InternalError: Timeout waiting for task consumption".

The sequence:

  1. The agent calls complete(). MainQueue marks the caller's ChildQueue as expecting a final event
    (expectFinalEvent / submitExpectedFinalEvent) and submits the event to the MainEventBus.
  2. ResultAggregator already returned to onMessageSend on the first event (WORKING). The agent returns,
    and step 2 of the blocking handling closes the child queue with queue.close(false, false).
  3. MainEventBusProcessor persists the final event and calls distributeToChildren, which skips the child
    because child.isClosed() is true, although the child is still awaiting that event.
  4. EventConsumer keeps polling while isAwaitingFinalEvent() is true, until MAX_AWAITING_FINAL_TIMEOUT_MS
    (3 s) runs out. Only then does step 3 complete.

This is a regression in 1.4.0.Final. The skip in distributeToChildren came in with dabca6c
("fix(server): recover failed terminal enqueues and fix EventQueue close races"); 1.3.2.Final delivers to
every child, and the same test passes there. The comment above the skip says a final event cannot be in
flight for a closed child, because closeIfNotAwaitingFinalEvent() prevents that. Step 2 in
DefaultRequestHandler closes with close(false, false), which does not look at those counters.

Expected: the blocking call returns the completed task as soon as the final event is persisted.

To reproduce: a test in DefaultRequestHandlerTest that holds the agent's next event in the event bus
(a MainEventBusProcessorCallback that blocks on the WORKING event) until the agent has returned and the
handler has closed the queue. It passes on 1.3.2.Final and fails on 1.4.0.Final; main has the same code
as 1.4.0.Final.

A possible fix, which makes the test pass with all server-common tests green:

if (child.isClosed() && !child.isAwaitingFinalEvent()) {

A gracefully closed child still drains its queue, so delivering the final event it was told to expect
lets the consumer finish at once. I can open a PR with the test and this change.

Relevant log output
DefaultRequestHandler: Step 2 - Closed queue for task b6db44c8-... to allow consumption completion
MainQueue[b6db44c8-...]: Skipping closed child queue for event TaskStatusUpdateEvent
Agent completed, awaiting final event (timeout 1/6), continuing to poll (queue=16373883)
Agent completed, awaiting final event (timeout 2/6), continuing to poll (queue=16373883)
Agent completed, awaiting final event (timeout 3/6), continuing to poll (queue=16373883)
Timeout waiting for task b6db44c8-... consumption
Langage dominant
Java
Étoiles
510
Forks
196
Merge moyen
2 j 22 h
PR mergées (30 j)
31

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de a2aproject/a2a-java

Toutes les issues de a2aproject/a2a-java

Issues similaires

Plus d'issues Java

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.