R7.01.2 · dive 2
Refuse the write, keep the record.
maxmemory-policy is a menu. The cache policies delete keys under pressure to keep
serving; noeviction refuses the write instead — so nothing stored is ever lost.
If Valkey holds the record of truth, eviction is silent data loss: a job, a leaderboard row,
a guess lock, gone with no trace. A system of record runs noeviction, and memory pressure becomes
a loud error to alert on, not a vanished record. Select a policy; the readout reports what it sacrifices at the
cap — a stored key, or the incoming write.
maxmemory cap?
Select a policy; the readout reports what it drops to satisfy a write.The same write, two postures
noeviction.md · under pressurePut the same write — a new job row at a full keyspace — to two servers, one on allkeys-lru
and one on noeviction, and the divergence is the whole lesson. Under allkeys-lru the
write succeeds, but to make room the server deletes the key it judges coldest. If that key was the only copy
of a record, it is gone — silently, with nothing in the response to say so. Under noeviction
the write fails with an OOM error, nothing stored is lost, and the alert fires on used_memory
crossing the threshold.
The trade is one-directional: noeviction gives up accepting writes under pressure and
buys the guarantee that no stored record is ever dropped. For a cache that is the wrong trade; for a record of
truth it is the only acceptable one.
In EchoMQ — the job HASH is the record of truth
infra/valkey/conf/valkey.conf · the tuning surfaceEchoMQ's job row has no second canonical copy. The enqueue script writes the row in one atomic step —
HSET emq:{q}:job:<JOB-id> state pending attempts 0 payload <body> — and
claim / complete / retry mutate that same HASH. There is no shadow
row in Postgres to fall back on if the key disappears. That is why EchoMQ's Valkey runs noeviction:
an evicted job key is a lost job, and a queue that silently drops keys is a queue that silently loses work.
# Memory: a loud guardrail, not a working ceiling. # noeviction means a runaway keyspace REJECTS writes loudly instead of being OOM-killed silently. maxmemory 512mb maxmemory-policy noeviction maxmemory-clients 64mb # Fail the write rather than acknowledge data that may not survive. propagation-error-behavior panic
Two design choices ride alongside it. First, maxmemory is a guardrail set far above the working
set, not a working ceiling — the live dataset is single-digit megabytes, so 512 MB leaves roughly half
the box for fork copy-on-write and buffers, and the cap exists to turn a runaway into an alert long before the
OOM killer acts. Second, propagation-error-behavior panic makes the server fail a write rather than
acknowledge data that may not survive — the same posture as noeviction, applied to propagation
rather than to memory: refuse, do not pretend.
Eviction is the wrong posture for a job store: a queue that silently drops keys is a queue that silently loses work, so memory pressure must surface as write errors and alerts.
Notes on Valkeymaxmemory-policy selects what happens at the
maxmemory cap: the allkeys-* policies evict from the whole keyspace, the
volatile-* policies evict only keys with a TTL, and noeviction rejects writes with an
OOM error while continuing to serve reads —
valkey.io/topics/lru-cache.
The eviction-policy menu: cache policies delete a key under pressure to keep serving; noeviction
refuses the write instead, so nothing stored is lost.
EchoMQ chooses noeviction because the emq:{q}:job HASH is the record of truth —
an evicted key is a lost job. maxmemory is a guardrail far above the working set, paired with
propagation-error-behavior panic.
The eviction policy is the line between a cache and a system of record. EchoMQ runs
noeviction because the job HASH has no second home: memory pressure must surface as a write error and
an alert, never as a vanished job.
The production posture of this config
This is the committed tuning surface; its production reasoning — why maxmemory sits far above
the working set, how the fork copy-on-write spike is budgeted, and why eviction is the wrong posture for a job
store — is the subject of Valkey on a Fly machine in the
Branded Component System course. The persistence side of the same record-of-truth posture is the
next dive.
References
sources · relatedSources
- Valkey — Key eviction — the
maxmemory-policymenu: the LRU/LFU approximations, the volatile vs allkeys split, andnoeviction. - Valkey — CONFIG SET — set
maxmemoryandmaxmemory-policyat runtime, without a restart. - Valkey — Persistence — AOF and RDB, the durability beneath the record of truth this policy protects.
- Valkey — HSET — the command that writes the job HASH the eviction policy must never drop.
Related in this course
- R7.01 · Redis as a primary databasethe module hub: the store as the system of record
- R7.01.1 · System of recordthe row is the record, and the per-datum decision
- R7.01.3 · PersistenceRDB vs AOF; the durability bound under the record
- /bcs · Valkey on a Fly machinethe production posture of this exact config