Skip to content

fix(services): make the Redis and Valkey health checks prove a write - #78

Merged
vishr merged 1 commit into
mainfrom
fix/redis-health-is-write-sensitive
Aug 19, 2026
Merged

fix(services): make the Redis and Valkey health checks prove a write#78
vishr merged 1 commit into
mainfrom
fix/redis-health-is-write-sensitive

Conversation

@vishr

@vishr vishr commented Aug 19, 2026

Copy link
Copy Markdown
Member

Closes #76.

The defect

redis-cli -a "$REDIS_PASSWORD" ping | grep -q PONG

Redis answers PONG while refusing every write. When a background save fails and stop-writes-on-bgsave-error is enabled — Redis's own default — the server serves reads and replies MISCONF to writes. Valkey has the same shape.

Onebox gates rollouts on that answer. So the probe certified the service healthy exactly when the behaviour its callers depend on was gone: dependent workloads started, the deploy converged, and every counter, session, queue and rate-limiter write failed against a dependency the system had just approved.

The fix

redis-cli -a "$REDIS_PASSWORD" set ob:health 1 EX 30 | grep -qx OK

SET exercises the path the probe is meant to cover, and MISCONF fails it. The key is namespaced so it cannot collide with an application key, and EX bounds it — one key held, never accumulated.

grep -qx rather than grep -q '^OK$' is deliberate. The anchored form reads better and would have been wrong: escapeDollars doubles every $ in generated content, so $ would have reached Compose as $$ and been interpolated. Whole-line matching needs no $. Verified in the rendered output — the credential still renders -a "$$REDIS_PASSWORD", unchanged.

Scope, shown by the digests

Six frozen corpus digests move, all of them redis=. Application digests and every other service digest are byte-identical:

lines mentioning redis or valkey: 12
lines without them: 0

That is the evidence this touched only the two drivers it claims to.

Operational note

This is a service-definition change: the first deploy after upgrading recreates the redis and valkey services. Unavoidable — the old definition is the defect.

Tests

Regression tests assert the probe writes, has a TTL, keeps the escaped credential, carries no unescaped $, and explicitly guard against a return to a connection-only ping. Non-vacuous, verified by restoring the ping probe:

--- FAIL: TestRedisFamilyHealthChecksProveAWrite
    redis health check does not write

Verified

just check, golangci-lint run ./..., go test -race ./....

Related

Sequencing note for #75: with AOF disabled on ephemeral Redis, the stop-writes-on-bgsave-error path largely disappears, so this probe's value differs by persistence mode. Landing it first means #75 inherits a write-sensitive probe rather than having to add one.

The native probes asked whether the server answers:

    redis-cli -a "$REDIS_PASSWORD" ping | grep -q PONG

Redis answers PONG while refusing every write. When a background save fails and
stop-writes-on-bgsave-error is enabled — Redis's own default — the server keeps
serving reads and replies MISCONF to writes. Valkey has the same shape.

So the probe reported the service healthy exactly when the behaviour its callers
depend on was gone. Onebox gates rollouts on that answer, so dependent workloads
started, the deploy converged, and every counter, session, queue and rate-limiter
write failed against a dependency the system had just certified. An application
that fails open on a rate-limit increment does so at the moment it is least
supposed to.

Both drivers now write:

    redis-cli -a "$REDIS_PASSWORD" set ob:health 1 EX 30 | grep -qx OK

SET exercises the path the probe is meant to cover, and MISCONF fails it. The
key is namespaced so it cannot collide with an application's, and EX bounds it,
so the probe holds one key rather than accumulating them.

`grep -qx` rather than an anchored pattern is deliberate. `grep -q '^OK$'` reads
correctly and would have been wrong here: escapeDollars doubles every `$` in
generated content, so the anchor would have reached Compose as `$$` and been
interpolated. Matching the whole line needs no `$` at all. The generated
credential still renders as `-a "$$REDIS_PASSWORD"`, unchanged.

Six frozen corpus digests move, all of them `redis=`. The application digests
and every other service digest are byte-identical, which is the evidence that
this touched only the two drivers it claims to.

Operationally this is a service-definition change: the first deploy after
upgrading recreates redis and valkey services. That is unavoidable — the old
definition is the defect.

Tests fail without the fix, checked by restoring the ping probe and watching
them go red rather than assumed.

Closes #76.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vishr
vishr merged commit 48c7a3f into main Aug 19, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make Redis and Valkey health checks write-sensitive

1 participant