Skip to content
pg_redis
Esc
navigateopen⌘Jpreview
On this page

Commands

Supported Redis commands, Valkey compatibility, and TTL behaviour.

Current surface

Area Commands
Connection PING, ECHO, SELECT 0
Strings SET (NX/XX/EX/PX), SETNX, SETEX/PSETEX, GET, DEL, EXISTS, STRLEN, MGET/MSET/MSETNX, GETSET, APPEND, GETRANGE/SETRANGE
TTL EXPIRE/PEXPIRE, TTL/PTTL
Admin FLUSHDB/FLUSHALL, INFO
Harness stubs CONFIG, FUNCTION FLUSH

INFO returns server/memory/stats/keyspace plus pg_redis_* metadata; redis_version matches the Valkey compat pin.

Valkey compatibility

Pinned suite: Valkey 8.1.4 under compat/valkey/.

make compat   # Postgres up with in-process RESP gateway + allowlisted TCL

make compat passes --host/--port into Valkey’s harness (“external server” mode). That does not mean the standalone redis_gateway binary — it means “use the already-running embedded gateway on :6379” from make postgres-up.

Live status lives in compat/STATUS.md. Grow compat/allowlist.txt as commands land.

What the suite covers

Covered Not covered
Allowlisted TCL tests via Valkey’s RESP client Inline wire form (use make bench / raw-byte tests)
Embedded gateway + redis.* storage redis-benchmark throughput / PING_INLINE
Empty-string SET/GET; TTL (lazy + pg_cron sweeper) Full string suite leftovers

Green compat is necessary for semantic claims; it is not sufficient for inline protocol or benchmark defaults.

Protocol surfaces

Clients do not all speak the same wire form:

Surface Example Who uses it
RESP array (mbulk) *1\r\n$4\r\nPING\r\n redis-cli, most libraries, Valkey TCL client
Inline / telnet PING\r\n redis-benchmark ping / PING_INLINE, telnet
Pipelined many commands back-to-back redis-benchmark -P, busy clients

make compat and redis-cli exercise RESP arrays. They will not catch an inline-protocol regression. Default make bench uses redis-benchmark -t ping, which runs both PING_INLINE and PING_MBULK.

TTL / expiry

  1. Lazyexpires_at columns + redis.ensure_alive on read/write.
  2. Active (SQL modes)pg_cron job pg_redis_ttl_task (* * * * *) calls redis.delete_expired_keys().
  3. Active (memory mode) — 1s in-gateway tick calls MemoryStore::purge_expired().

Known limitation — naive active expiry

Path What we do now Gap vs Redis
Memory Full HashMap scan every 1s Redis samples a small random subset per tick
SQL (pg_cron) Delete up to batch × rounds rows per minute Coarser than Redis sampling cadence

SQL sweeper GUCs:

GUC Default Meaning
pg_redis.ttl_delete_batch_size 1000 Keys per DELETE round
pg_redis.ttl_delete_max_rounds 10 Rounds per CALL redis.delete_expired_keys()

Correctness (lazy-on-access + eventual active delete) is fine. Cost under large key counts is not.

Was this page helpful?