Skip to content

grpc-proxy: worker tunnel close reason is computed then discarded, making disconnects undiagnosable #596

Description

@balajinvda

Problem

grpc-proxy closes worker tunnel connections for several ordinary reasons: the worker connection cache TTL expiring, the connection going inactive, capacity eviction, and shutdown drain.

It already computes which reason applied, via mapEvictionReason, on every single close. That value is then written to a debug-level log and discarded:

cache.OnEviction(func(ctx, reason, i) {
    reasonStr := mapEvictionReason(reason)   // ttl_expired|deleted|capacity_reached|unknown
    zap.L().Debug("worker connection cache eviction triggered",
        zap.String("eviction_reason", reasonStr), ...)
    _ = wc.Close()
})

No metric. No span. Debug level, so effectively unavailable in production.

Impact

"Why did the tunnel drop?" cannot be answered from production data. It can only be inferred by reading source, or by enabling debug logging on a specific pod during a live reproduction.

There is also no telemetry of any kind on the proxy-to-worker leg. The existing metrics cover client connections and NATS, so an entire hop is unobserved, and it is the hop where connection-lifecycle failures occur.

This has been a concrete blocker on at least one long-running streaming-disconnect investigation, where the question "is the proxy dropping these connections, and if so why" stayed open for weeks despite the service knowing the answer every time it happened.

Proposal

Emit the reason that is already computed:

  • counter labelled by reason, bounded to four values, pre-initialised to zero
  • gauge for currently-open worker tunnels
  • histogram of tunnel duration, with buckets straddling the timers that can close one, so a timer kill shows as a cliff
  • promote the existing log line from debug to info, keeping the message text unchanged so existing searches keep working
  • span carrying request id, reason and duration, for correlation in tracing

No behaviour change; this is observability only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions