agentscope-ai / agentscope-ai/agentscope-java

[Bug]: a2a sse接口事件超过1000的时候会导致卡住

Abierto
#2,507 1 comentario 0 reacciones 0 asignados Ver en GitHub
area/ext/integration bug
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

# SSE 事件流卡在 1000 个事件问题 —— 根因分析与修复方案

## 1. 问题现象

- 测试脚本稳定复现:SSE 流式事件精确在第 **1000 个事件**处停止。
- 服务端最终报错:`TimeoutException: Did not observe any item or terminal signal within 600000ms`。
- 该问题与事件计数强相关(精确卡在1000),而非偶发网络抖动,多次测试均可复现。
- 已排除的错误方向:
- `JsonRpcTransportWrapper` 的 8192 容量 backpressure buffer(`onBackpressureBuffer` + `BufferOverflowStrategy.ERROR`)—— 容量远大于1000,且策略是抛错而非阻塞,现象不匹配。

## 2. 根因确认

问题根源在第三方闭源依赖 **`io.github.a2asdk:a2a-java-sdk-server-common`**(当前项目通过 `agentscope 2.0.0` 正式版间接引入,确认版本号为 **`0.3.3.Final`**,与之前排查的 RC3 版本一致,因此结论对当前正式版同样适用)。

### 2.1 核心类:`io.a2a.server.events.EventQueue`

通过反编译字节码(`javap -p -v`)确认:

1. **默认队列容量硬编码为 1000**
- 主构造函数:`EventQueue(int queueSize)`,内部创建 `new Semaphore(queueSize, true)`(fair 模式)。
- 子队列(父子关系)构造函数:`EventQueue(EventQueue parent)` 内部硬编码调用 `this(1000)`。
- 字节码证据:`sipush 1000` 出现在该构造函数中。

2. **`enqueueEvent()` 使用无超时的阻塞式 `acquire()`**
```
27: aload_0
28: getfield #39 // semaphore
31: invokevirtual #86 // Semaphore.acquire:()V <-- 无超时阻塞!
34: goto 55
...
55: aload_0
56: getfield #15 // queue: BlockingQueue
59: aload_1
60: invokeinterface #107 // BlockingQueue.add
```
- 每次入队前必须先拿到一个 `Semaphore` 许可;许可总数 = 队列容量(1000)。
- 只有消费者取出一个事件(`dequeueEventItem`)才会 `release()` 一个许可。
- **该 `acquire()` 调用没有超时参数**,如果没有可用许可,会无限期阻塞当前线程。

### 2.2 触发链路

1. Agent 执行过程中通过 `AgentScopeAgentExecutor` → `TaskUpdater` → `EventQueue.enqueueEvent()` 持续产生事件(reasoning/tool/artifact 等)。
2. 事件消费端是 SSE 输出(`JsonRpcTransportWrapper` → 客户端网络连接)。
3. **一旦消费速度跟不上生产速度**(例如客户端网络慢、下游处理阻塞等),未消费事件在队列中堆积。
4. 堆到 1000 个后,第 1001 次 `enqueueEvent()` 在 `semaphore.acquire()` 处**永久阻塞**——生产者线程被卡死,不再产生新事件。
5. 表现为“事件数精确停在1000”,且后续什么都不再发生。
6. 最终触发此前已加的 **30 秒空闲超时兜底机制**(`DynamicModelMiddleware` 中的 `resultFlux.timeout(Duration.ofSeconds(30))`),报错看起来像“模型超时”,但**真正原因是队列阻塞死锁,不是模型响应变慢**。

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.