feat: 添加 WithStreamErrors 查询流式调用执行过程中的异常

流式输出/双向流的 handler(Python 生成器)如果执行过程中抛异常,
Invoke[chan T] 本身的 err 只描述"调用有没有发起成功",跟这个异常
无关(永远是 nil),channel 只会静默提前关闭,调用方原本完全无法
感知。新增 WithStreamErrors(ctx) 返回一个包过的 ctx 和一个查询函数
streamErr,opt-in 之后可以查到具体错误。

错误记录挂在 WithStreamErrors 返回的 ctx 的对象图里(context.WithValue),
不是全局表——调用方不再引用 ctx/channel 时会被 GC 自然回收,不需要
任何显式清理逻辑,也不依赖 ctx.Done(),即使用 context.Background()
也能正常释放;ctx 之后被别的 context.With*(包括 StickyCtx)再包一层
也不影响查询。

同时补充完整的自动化测试覆盖 example/main.go 里演示过的所有功能:
四种调用模式 × int/struct/slice/[]byte 的组合(client_test.go)、
WithHandlers/call_go 全双工(handlers_test.go)、NewSession 隔离性
与 StickyCtx 路由(session_test.go),之前这些只能靠人肉跑 go run
看输出,现在都有真实断言。
This commit is contained in:
2026-07-23 16:24:05 +08:00
parent 6ccec66a1e
commit ee5e5b96af
9 changed files with 717 additions and 5 deletions
+6
View File
@@ -221,6 +221,9 @@ func invokeStreamOut[R any](ctx context.Context, pool Pool, method string, rt re
for {
msg, err := readResult(ctx, conn, pool, write)
if err != nil || msg.Type == TypeEnd || msg.Type == TypeError {
if msg.Type == TypeError {
recordStreamError(ctx, ch.Interface(), fmt.Errorf("remote error: %s", msg.Error))
}
return
}
if msg.Type == TypeChunk {
@@ -395,6 +398,9 @@ func invokeStreamBoth[R any](ctx context.Context, pool Pool, method string, stre
for {
msg, err := readResult(ctx, conn, pool, write)
if err != nil || msg.Type == TypeEnd || msg.Type == TypeError {
if msg.Type == TypeError {
recordStreamError(ctx, outCh.Interface(), fmt.Errorf("remote error: %s", msg.Error))
}
return
}
if msg.Type == TypeChunk {