Go E04:RPC 与流式调用怎样映射任务期限
E03把受控本地函数接在原服务分析器上。本篇沿用同一个累计任务服务的 HTTP/SQL 状态机,通过真正的 TCP gRPC 提交任务并流式看状态。核心不是给 202 换一种序列化格式,而是把 RPC 调用期限、服务端退出和任务终态分开。完整包、SHA-256、独立复跑随文交付。
先冻住传输约定
固定 Go 1.27.1,gRPC-Go google.golang.org/grpc v1.67.1,protobuf 间接依赖 v1.34.2;go.mod/go.sum 和实际 go list -m all 保留版本闭包。本篇使用 gRPC-Go 的 ServiceDesc 和强制 JSON codec,线协议是 application/grpc+json,并未提供 .proto 或生成跨语言 protobuf 客户端。这能实测同版本 Go 客户端与服务端的 RPC/stream 生命周期,但不能宣称默认 gRPC protobuf 客户端可互通。连接只走 loopback insecure.NewCredentials(),TLS、认证及远程网络为 NOT_RUN。
rpc_tasks.go:rpcTaskAdapter 没有新建业务状态机。Submit 把 RPC 字段交给原 taskHTTPService.Handler() 的 POST 入口:原 JSON/字段校验、排队/SQL 提交仍由同一服务负责,HTTP 400 被映射到 gRPC InvalidArgument。Watch 从原查询入口取状态后向 gRPC stream 发送转移事件;ID 不存在映射 NotFound。复用 HTTP handler 是本篇的明确适配取舍,增加一次编解码与 HTTP 语义依赖,不是独立的 proto 契约,更不能假装这里测了 HTTP 与 RPC 性能优劣。
一次取消有三种观察
隔离 PostgreSQL 16.15 的原任务分析器由闸门暂时停住。gRPC Submit("Go one") 真正接受并返回当前任务 ID;服务已入库且 worker 到达分析器,此时 Watch 流首先给出 RUNNING。客户端随后取消观察流,RecvMsg 返回 gRPC Canceled,SQL 同一 ID 仍为 RUNNING/words=0。取消流只结束观察者的期限,已接受任务属于服务,未被自动取消。
服务端 grpc.Server.GracefulStop 返回后,再查 SQL 仍是 RUNNING。官方 API 的等待范围是正在处理的 RPC,不是服务自有的任务 worker;此刻不能向客户报业务完成。释放分析闸门、调用原 taskHTTPService.Close() 等待 worker 后,SQL 才是 SUCCEEDED/words=2。十轮重复保留了客户端错误码、服务退出信号、实际 ID 和最终 SQL 状态各自的原始日志,没有把 gRPC 返回视为 SQL 终态。另一路正常流直到 SUCCEEDED/words=2 后收到 EOF,未知 ID 报 NotFound;空白提交为 InvalidArgument。
练习:①用户在收到提交 ID 后取消 Watch,能否向他报告「任务已取消」?答:不能。只有流结束,查询实际任务状态仍为 RUNNING;业务取消必须走原任务取消协议,随后再等退出。②GracefulStop 已返回意味着 worker 已释放数据库连接吗?答:不意味着;还得等待 taskHTTPService.Close 和独立的 SQL 终态。③只看到正常流 EOF 是否证明副作用完成?答:不证明;本服务的成功定义仅是统计结果已持久化,外部动作既未实现也未验收。
真正独立解包会重新下载固定 gRPC 依赖、初始化新 PostgreSQL,在新 Go 模块/编译缓存下执行十轮 TCP/SQL 正反实验、全包测试/race 和旧 CLI,再分开检查 Hexo 页面与下载。race 没有报告只限这些路径;其他平台、TLS、proto 互通、远端、外部动作去重、全站构建及发布仍 NOT_RUN。E05继续限定适配层的范围。
参考资料
- gRPC-Go v1.67.1
grpc.Server.GracefulStop、grpc.ServiceDesc、encoding.Codec:本机已冻结 module 的go doc、Go module 版本与真实源码 SHA 在evidence/E04/。






