Skip to content

[nats] Close(ctx) 落在重连窗口返回虚假错误——上游已强制关闭连接(目标态达成)却报 "drain: connection reconnecting",与自家「目标态已达成不算错误」口径相反 #147

Closed

Description

@zy84338719

现象

nats/client.go:178-187:

	if err := c.conn.Drain(); err != nil {
		c.conn.Close()
		// 被释放。网络侧已关闭(ErrConnectionClosed)时目标态已达成,
		if !errors.Is(err, nats.ErrConnectionClosed) {
			closeErr = fmt.Errorf("nats: drain: %w", err)

注释(client.go:163)自述「Drain 被拒绝启动(如连接已被网络侧关闭)视为已达目标态」。但 nats.go v1.55.0 的 Drain()(nats.go:6501-6511)在连接重连中时执行 nc.Close(); return ErrConnectionReconnecting——连接已被强制关闭、正是关停想要的结果,却因不匹配 ErrConnectionClosed 被记成失败。

探针复现(服务端 Shutdown 后 500ms 调 Close):

[natsclose] connected after shutdown: false
[natsclose] Close(ctx) returned: nats: drain: nats: connection reconnecting

失败场景推演

优雅关停/滚动升级恰逢 NATS 闪断(服务重启、网络抖动),defer c.Close(ctx) 落在重连窗口 → 返回非 nil 错误。上层关停逻辑按错误处置:告警误报、进程非零退出码、或跳过后续清理——而连接其实已关、目标态已达成。0.x 下游凡是「Close 返回 err 就 fail shutdown」的代码都会被它污染。

为什么测试没抓到

nats_embedded_test.go:29 显式 WithMaxReconnects(0) 且注释「tests don't exercise reconnect」——重连状态机整个不在测试面内;Close 测试都在连接健康时调用。

建议修复方向

错误分类把 nats.ErrConnectionReconnecting(连接已被上游关闭)与 ErrConnectionClosed 同列「目标态已达成」豁免;顺带防御 ErrConnectionDraining(v1.55.0 幂等 Drain 返回 nil,但其它版本/竞态下语义不同)。


置信度:高(探针复现拿到原文错误串 + nats.go:6507-6510 上游行为逐行核实;基线 = network 9f3d2c3)

与既有 issue 的差异:#83/#86 修的是「无超时 Drain 永久阻塞关停」(已由 Close(ctx) 修复,CHANGELOG PR #91);本条是该修复的错误口径残口——目标态豁免只写了 ErrConnectionClosed 一种,重连窗口的同为「已关」状态被误分类。delta 明确。

Activity

  1. added a commit that references this issue on Nov 10, 2026
  2. zy84338719 commented on Nov 10, 2026

    @zy84338719
    ContributorAuthor

    已在 v0.9.2 修复并发布 ✅

    变更内容

    本条修复(在 v0.9.2 的版本节里定位到):

    该版本 `v0.9.2` 的其余变更

    关联问题单:#145。

    关联问题单:#146。

    关联问题单:#147。

    Release: https://github.com/oekit/network/releases/tag/v0.9.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions