Skip to content

fix(deps): update module github.com/redis/go-redis/v9 to v9.22.0 - #46

Open
sparedark wants to merge 1 commit into
mainfrom
renovate/github.com-redis-go-redis-v9-9.x
Open

fix(deps): update module github.com/redis/go-redis/v9 to v9.22.0#46
sparedark wants to merge 1 commit into
mainfrom
renovate/github.com-redis-go-redis-v9-9.x

Conversation

@sparedark

@sparedark sparedark commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
github.com/redis/go-redis/v9 v9.20.1v9.22.0 age confidence

Release Notes

redis/go-redis (github.com/redis/go-redis/v9)

v9.22.0: 9.22.0

Compare Source

This is a minor release introducing two flagship (experimental) features — client-side caching and automatic pipelining — alongside support for Redis 8.10, new commands, and a large batch of stability and parser-robustness fixes. It consolidates everything shipped in 9.22.0-beta.1, so the notes below cover the full 9.21.0 → 9.22.0 upgrade.

⚠️ Two changes to be aware of when upgrading from 9.21.0:

  • Default configuration values changed (#​3918): read/write timeouts, retry backoff, cluster state reload interval, and TCP keep-alive defaults are now aligned with the cross-SDK configuration proposal (see the highlight below). Explicitly configured values are unaffected.
  • WaitAOF return type corrected (#​3888): WaitAOF now returns *IntSliceCmd, matching the two-integer reply of WAITAOF (previously *IntCmd, which failed to parse the reply at runtime). Code referencing the old return type needs a one-line update.

🚀 Highlights

Client-Side Caching (Experimental)

The standalone Client gains server-assisted client-side caching built on RESP3 CLIENT TRACKING. Enable it by setting ClientSideCacheConfig in Options (or supply your own cache via ClientSideCache — e.g. to share one cache across clients). Cacheable read results are served from a local in-process cache and invalidated automatically when the server reports a change, cutting round trips for read-heavy workloads.

The invalidation architecture is selected by ClientSideCacheStrategy; the default (and currently only) strategy is CSCStrategySharedTracking: one shared cache, every pool connection runs plain CLIENT TRACKING ON, and a background drainer applies buffered invalidations — portable (no BCAST) and consistent with the other Redis client libraries. Requirements and guardrails: RESP3 (Protocol: 3), standalone client, DB 0 only; commands that would change the connection identity (SELECT, AUTH, ...) are rejected while caching is enabled, and CSC is disabled when a credentials provider is set (fixed Username/Password work and are namespaced). See the README's client-side caching section and the runnable example.

Experimental: the API may change in a minor release.

(#​3941) by @​ofekshenawa

Automatic Pipelining (Experimental)

AutoPipeliner is a background batcher that coalesces commands from many concurrent goroutines into Redis pipelines, multiplying throughput without any manual pipeline management. It comes in two faces, available on Client and ClusterClient (and configurable via Options.AutoPipelineOptions / UniversalOptions.AutoPipelineOptions):

  • AutoPipeline() — the blocking face: a drop-in Cmdable where each call blocks until executed, exactly like a plain client, while concurrent callers' commands batch together under the hood (measured locally over loopback: ~1M+ SET/sec vs ~100k unpipelined; indicative, not a guarantee). Per-goroutine command order is preserved.
  • AsyncAutoPipeline() — the deferred face: command calls return immediately and every typed result accessor (Val/Result/Err/...) blocks until the command has executed. Submit a window of commands, then read the results, to keep pipelines deep (~2–3M SET/sec locally; indicative).

AutoPipelineOptions controls batching: MaxBatchSize (soft target, default 200; the blocking face's preset uses 300), MaxBatchBytes (approximate payload cap so huge values flush as several bounded writes), MaxFlushDelay with optional AdaptiveDelay (delay scales down as the queue fills), and MaxConcurrentBatches (default 1 = a single ordered batch stream; raising it requires Unordered: true, so ordering is never lost by accident — Validate() rejects the combination otherwise). A usage tour and throughput comparison live in example/autopipeline.

Experimental: the API may change in a future release — pin your go-redis version if you adopt it.

(#​3942) by @​ndyakov, with help from @​cxljs

Redis 8.10 Support

This release adds support for Redis 8.10. The README's supported-versions list now includes Redis 8.10, and CI runs the full suite against the redislabs/client-libs-test:8.10.0 image by default (#​3920, #​3940).

Coverage for the new commands and options that ship with Redis 8.10:

  • HIMPORT (#​3919) — bulk hash import via server-side fieldsets, exposed as HImportPrepare, HImportSet, HImportDiscard, and HImportDiscardAll. Fieldsets are session state scoped to a single physical connection, which does not mix well with connection pooling — so the client keeps a versioned fieldset registry and lazily replays the PREPARE on whichever pooled connection executes a SET that needs it, at most once per connection, with no extra round trip (the PREPARE is injected into the same write as the SET).
  • LMOVEM / BLMOVEM (#​3913) — move multiple elements between lists in one call.
  • SUNIONCARD / SDIFFCARD (#​3897) — cardinality of set union/difference without materializing the result.
  • XREAD / XREADGROUP MAXCOUNT and MAXSIZE (#​3898) — bound how much data a stream read returns.
  • TS.READ (#​3896), TS.QUERYLABELS (#​3926), TS.NRANGE / TS.NREVRANGE (#​3870) with multiple aggregators per key (#​3937), and EXCLUDEEMPTY on TS.MRANGE / TS.MREVRANGE (#​3912) — new time-series query surface.
  • FT.ALIASLIST (#​3925), COLLECT reducer for FT.AGGREGATE (#​3886), RERANK on HNSW vector fields in FT.CREATE (#​3927), and FT.HYBRID timeout warnings (#​3911) — search coverage.
Cross-SDK Aligned Defaults

Default configuration values now follow the cross-SDK configuration proposal shared by all Redis client libraries (#​3918):

Setting Old default New default
ReadTimeout / WriteTimeout 3s 5s
Retry backoff (min/max) 8ms / 512ms 10ms / 1s
Cluster state reload interval 10s 60s
TCP keep-alive 5min period 30s idle / 5s interval / 3 probes (net.KeepAliveConfig)

Applications that set these values explicitly are unaffected; applications relying on the old defaults inherit the new ones.

Data-Race and Parser Hardening Sweep

A systematic audit fixed data races across the client — hooks (AddHook, #​3868), Ring.SetAddrs (#​3862), cluster node slices (#​3861), pub/sub reconnect (#​3906), maintenance notifications (#​3894, #​3872), pool handoff (#​3876), and redisotel (#​3881) — and hardened the RESP parsers against malformed or unexpected replies: over-reads on nil replies (#​3874), integer overflow when skipping map/attribute bodies (#​3877), unhashable RESP3 map keys (#​3873), odd-length flat replies (#​3900), mismatched declared array lengths (#​3907), unexpected extra reply frames (#​3884), and nil elements in numeric/bool slice replies (#​3922).

PubSub Receive Hang Fix

PeekPushNotificationName blocked until 36 bytes were buffered, so a short subscribe confirmation (channel name of six or fewer characters) on an otherwise idle connection hung PubSub.Receive forever — a regression introduced in 9.20.1 by #​3842. The peek now parses whatever is already buffered and only waits for one more byte when the frame prefix is valid but incomplete. Fixes #​3935.

(#​3936) by @​ndyakov

Correct Cluster Transaction Retries

The cluster transaction pipeline treated a MULTI...EXEC block as independently retryable commands, which could scatter a transaction across nodes or send malformed transactions on retry. Redirects (MOVED/ASK/TRYAGAIN) and aborts are now handled at the whole-transaction level, matching Redis transaction semantics: the transaction is re-routed and retried as a unit, never partially (#​3909) by @​cxljs.

Credential Redaction in Command Tracing

rediscmd.AppendCmd — used by redisotel and rediscensus to render commands into span attributes — now redacts credential arguments as <redacted>: AUTH, HELLO ... AUTH, CONFIG SET of requirepass / masterauth / TLS key passphrases, ACL SETUSER password rules, and MIGRATE ... AUTH/AUTH2. The client sends HELLO ... AUTH on every handshake and AUTH on every streaming-credentials rotation through the regular hook chain, so tracing hooks previously captured credentials even when the application never issued an auth command itself (#​3939) by @​saddamr3e.

✨ New Features

  • Client-side caching: server-assisted caching for the standalone client via ClientSideCacheConfig / ClientSideCache, with the CSCStrategySharedTracking invalidation strategy (#​3941) by @​ofekshenawa
  • Automatic pipelining: AutoPipeline() (blocking) and AsyncAutoPipeline() (deferred results) on Client and ClusterClient, configured via AutoPipelineOptions (#​3942) by @​ndyakov, with help from @​cxljs
  • HIMPORT command family: HImportPrepare / HImportSet / HImportDiscard / HImportDiscardAll with lazy per-connection fieldset prepare replay (#​3919) by @​ndyakov
  • LMOVEM / BLMOVEM: move multiple list elements in one call, with COUNT (up to N) or EXACTLY (all-or-nothing) semantics via LMoveMArgs (#​3913) by @​ofekshenawa
  • SUnionCard / SDiffCard: cardinality of set union/difference (#​3897) by @​ofekshenawa
  • XRead / XReadGroup MAXCOUNT / MAXSIZE: bound stream read responses by entry count or payload size (#​3898) by @​ofekshenawa
  • TS.READ: read samples from a series starting at a given timestamp, with TSReadEarliest (-), TSReadLatest (+), and TSReadNew ($) sentinels (#​3896) by @​ofekshenawa
  • TS.QUERYLABELS: query label names/values across time series (#​3926) by @​ndyakov
  • TS.NRANGE / TS.NREVRANGE: range queries across multiple series (#​3870) by @​ofekshenawa, with multiple aggregators per key (#​3937) by @​ndyakov
  • TS.MRANGE / TS.MREVRANGE EXCLUDEEMPTY: skip series with no samples in the result (#​3912) by @​ofekshenawa
  • FT.ALIASLIST: list all index aliases (#​3925) by @​ndyakov
  • FT.AGGREGATE COLLECT reducer: collect grouped values into an array (#​3886) by @​ndyakov
  • FT.CREATE RERANK: RERANK parameter on HNSW vector field definitions (#​3927) by @​ofekshenawa
  • FT.HYBRID timeout warnings: timeout warnings are now populated in hybrid search results (#​3911) by @​ofekshenawa
  • FT.HYBRID KNN SHARD_K_RATIO (Redis 8.8+): per-shard K ratio for KNN clauses (#​3841) by @​ndyakov

🐛 Bug Fixes

  • PubSub Receive hang: peek push-notification names without demanding 36 buffered bytes, fixing a hang on short subscribe confirmations (fixes #​3935, regression from 9.20.1) (#​3936) by @​ndyakov
  • Cluster transactions: re-route the whole tx pipeline on redirect/abort instead of per-command (#​3909) by @​cxljs
  • Credential leak in traces: rediscmd.AppendCmd redacts credential arguments (AUTH, HELLO ... AUTH, CONFIG SET secret params, ACL SETUSER password rules, MIGRATE AUTH/AUTH2), so redisotel / rediscensus span attributes no longer contain passwords (#​3939) by @​saddamr3e
  • WaitAOF return type: returns *IntSliceCmd matching the two-integer WAITAOF reply (#​3888) by @​CipherN9
  • Ring.Publish routing: publish to the shard that owns the topic instead of a round-robined one (#​3893) by @​dkindel
  • Pool OnRemove hooks: fire OnRemove on putConn eviction paths so removal hooks see every evicted connection (#​3932) by @​cxljs
  • UniversalClient InfoMap: added InfoMap to the Cmdable interface (#​3904) by @​nazarli-shabnam
  • SlowLogGet context: pass the caller's context instead of a background one (#​3915) by @​sonnemusk
  • ModuleLoadex nil config: return an error instead of panicking on nil config (#​3916) by @​sonnemusk
  • ParseURL IPv6 hosts: keep single brackets for IPv6 hosts without a port (#​3882) by @​sueun-dev
  • ParseURL durations: treat unit durations <= 0 as disabled (#​3866) by @​sueun-dev
  • Nil *uint8 encoding: encode nil *uint8 as "0" like other numeric pointers (#​3869) by @​sueun-dev
  • JSONSliceCmd read errors: return the read error from readReply instead of swallowing it (#​3903) by @​saddamr3e
  • RESP parser hardening: reconcile declared entry-array lengths (#​3907), handle nil elements in int/uint/bool slice parsers (#​3922), drain unexpected reply frames (#​3884), reject odd-length flat replies in Z/KeyValue parsers (#​3900), avoid int overflow when skipping map/attr bodies (#​3877), don't over-read nil replies in Reader.Discard (#​3874) by @​saddamr3e; reject unhashable keys in RESP3 map parsing (#​3873) by @​iabdullah215
  • Data races: hook state during AddHook (#​3868), onNewNode during Ring.SetAddrs (#​3862), shared masters/slaves slices in cluster (#​3861), shared opt.Addr during pub/sub reconnect (#​3906), clusterStateReloadCallback in maintnotifications (#​3894), conn reader in isHealthyConn during handoff (#​3876) by @​saddamr3e; handoff race window in maintnotifications (#​3872) by @​ndyakov
  • redisotel: use ObservableCounter for cumulative pool stats (#​3914) by @​Solaris-star; avoid a data race on shared attributes during MinIdleConns warmup (#​3881) by @​ndyakov

🧰 Maintenance

  • Cross-SDK default alignment: new defaults for timeouts, retry backoff, cluster state reload, and TCP keep-alive (#​3918) by @​ndyakov
  • CI on Redis 8.10: 8.10 made the default test version (#​3920) with version gating by major.minor (#​3908) by @​ofekshenawa; the test stack now runs the GA redislabs/client-libs-test:8.10.0 image and 8.8 was dropped from the CI matrix (#​3940)
  • Type-safe atomics: use typed sync/atomic value types (#​3860) and remove the dead assertUnstableCommand RESP3 path (#​3928) by @​cxljs
  • Docs: clarify that ExpireTime / PExpireTime return Unix timestamps (#​3917) by @​sonnemusk; remove a duplicate example step (#​3875) by @​andy-stark-redis

👥 Contributors

We'd like to thank all the contributors who worked on this release!

@​andy-stark-redis, @​CipherN9, @​cxljs, @​dkindel, @​iabdullah215, @​nazarli-shabnam, @​ndyakov, @​ofekshenawa, @​saddamr3e, @​Solaris-star, @​sonnemusk, @​sueun-dev


Full Changelog: redis/go-redis@v9.21.0...v9.22.0

v9.21.0: 9.21.0

Compare Source

This is a minor release adding new features and bug fixes. There are no breaking changes; upgrading from 9.20.x is a drop-in replacement.

🚀 Highlights

Zero-copy GetToBuffer / SetFromBuffer

Two new StringCmdable methods let callers read and write Redis string values directly into and from pre-allocated byte buffers, eliminating the per-call payload allocation that Get/Set incur:

GetToBuffer(ctx, key, buf) *ZeroCopyStringCmd   // reads into buf; ZeroCopyStringCmd { Val() int; Bytes() []byte; Result() (int, error) }
SetFromBuffer(ctx, key, buf) *StatusCmd

GetToBuffer decodes the bulk reply straight into the caller-owned buf (no intermediate allocation); a buffer that is too small returns an error after draining the payload, so the connection stays aligned for the next reply. SetFromBuffer is provided for API symmetry — it dispatches to the same []byte writer path as Set(ctx, key, buf, 0) and produces byte-identical output on the wire. Available on *Client, *ClusterClient, *Ring, *Conn and Pipeliner.

(#​3834) by @​ndyakov

Explicit LIMIT 0 for stream trimming

Redis treats XTRIM/XADD approximate-trim (~) LIMIT 0 as "disable the trimming effort cap entirely", which differs from omitting LIMIT (the implicit 100 * stream-node-max-entries default). The command builders previously only emitted LIMIT when limit > 0, so callers could never send an explicit LIMIT 0. Following the KeepTTL = -1 precedent, the new XTrimLimitDisabled = -1 sentinel now emits an explicit LIMIT 0; limit == 0 keeps the historical no-LIMIT behavior, so existing callers produce byte-identical commands.

(#​3848) by @​TheRealMal

✨ New Features

  • Zero-copy buffer string commands: new GetToBuffer / SetFromBuffer on StringCmdable and the ZeroCopyStringCmd result type, reading/writing string values into caller-owned buffers without per-call payload allocation (#​3834) by @​ndyakov
  • XTrimLimitDisabled sentinel: XTRIM/XADD approximate trimming can now send an explicit LIMIT 0 to disable the trim effort cap, via the new XTrimLimitDisabled = -1 sentinel (#​3848) by @​TheRealMal
  • PubSub health-check timeouts: channel.initHealthCheck now bounds the Ping it issues with a fresh per-check timeout context (the exported pingTimeout / reconnectTimeout) instead of context.TODO(), so a stuck health-check Ping can no longer block indefinitely (#​3819) by @​abdellani
  • Skip redundant UNWATCH in Tx.Close: a transaction now tracks whether a WATCH is still active (watchArmed) and only issues UNWATCH on Close when it is, removing an extra round trip on the common WATCH/.../EXEC and no-key Watch paths while never returning a connection to the pool with an active watch (#​3854) by @​fcostaoliveira

🐛 Bug Fixes

  • maintnotifications ModeAuto fail-open: ModeAuto now stays fail-open when the server does not support maintenance notifications — connections are retired and tracking is guarded during downgrade so the client keeps working instead of erroring (#​3853) by @​terrorobe

👥 Contributors

We'd like to thank all the contributors who worked on this release!

@​abdellani, @​fcostaoliveira, @​ndyakov, @​terrorobe, @​TheRealMal


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

@sparedark
sparedark force-pushed the renovate/github.com-redis-go-redis-v9-9.x branch from ae3eeb5 to 1cc6862 Compare August 9, 2026 00:40
@sparedark sparedark changed the title fix(deps): update module github.com/redis/go-redis/v9 to v9.21.0 fix(deps): update module github.com/redis/go-redis/v9 to v9.22.0 Aug 9, 2026
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.

2 participants