feat(observability): record Redis connection state on failed slot operations

Merged
WA
2mo ago
+337-16

Summary

A Redis command that never gets a reply fails identically in three very different situations, and nothing we record distinguishes them:

SituationWhat we'd want to see
Connection still being establishedstatus: connecting, non-zero queue depth
Reconnecting, command parked in the offline queuestatus: reconnecting, non-zero queue depth
Socket silently deadstatus: ready, queue depth 0

ioredis reports all three as Error: Command timed out with only its own timer frames in the stack — no app frame naming the call, no lifecycle event saying which happened. Today the cause can only be inferred from timing.

  • Adds describeRedisConnection() — client status, connection and ready ages, offline-queue depth, lifecycle counters (connects/reconnects/errors + last error), and whether the configured host is an IP literal or a DNS name.
  • Attaches it to the usage-reservation slot operations. Those are the first Redis calls a queued workflow makes, so an unusable connection surfaces there first.
  • connect and ready now log elapsed-since-construction, making the wait before a connection becomes usable directly measurable. Today that wait is spent inside a command's deadline, where it reads as a command timeout rather than as connection latency.
  • Extends the shared redisConfigMock, which documents that every export of the real module is present.

Why these fields

  • status is usually decisive on its own.
  • queuedCommands confirms it: a command parked in the offline queue was waiting on connection setup, whereas one written to a ready socket that never answered means the socket died without anything reporting it. ioredis has no public accessor for the offline queue, so this reads it through a narrow interface with a double-cast-allowed annotation.
  • hostKind rules DNS resolution in or out. No server-side telemetry can see a slow or retrying resolve — not VPC flow logs, not NLB counters, not cache metrics — so without this it stays a permanent unknown.

Security

REDIS_URL carries the AUTH token and is never logged. Only derived facts (IP vs DNS, TLS on/off, SNI override in play) are emitted. There's a test asserting the snapshot cannot contain the host, and I verified it fails if the URL is leaked into the payload.

Type of Change

  • Observability / diagnostics (no behavior change)

Testing

No behavior change: this adds a read-only snapshot and log fields. No timeouts, retry policy, or control flow were touched.

New tests cover no-client, connecting vs ready, offline-queue depth, lifecycle counting, IP vs DNS classification, and the secret-leak guard. Verified each fails for the right reason — forcing status to a constant breaks the discriminator tests, and leaking the URL into the snapshot breaks the secret test.

bun run type-check clean in apps/sim and packages/testing. 3149 tests pass across lib/core, lib/billing, lib/execution, background, plus 40 in packages/testing. bun run lint and all 37 audits pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)