NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules, #142 by repository stars
Latest stable
v9.23.0
Last release today
13 Nov 2026
Ships on a steady schedule
a new release about every 9 days
Some releases are documented
notes for 18 of 44 stable releases
5 versions withdrawn
withdrawn after publishing
4 years old
558 releases · first in 2023
Drag across the ruler to compare, or tap a release to open it.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
docs(release): scope FD Pipeline, MaxQueuedCommands, LRUClock
chore(release): v9.23.0
docs(release): scope FD Pipeline, MaxQueuedCommands, LRUClock
This is a minor release. It contains everything from 9.23.0-beta.1, so these notes cover the full 9.22.0 → 9.23.0 upgrade.
⚠️ Changes to check when you upgrade from 9.22.0:
go directive of the root module and of the submodules moved from 1.24 to 1.26, as part of the dependency bumps for govulncheck findings. Projects that build with Go 1.24 or 1.25 must upgrade the toolchain.Client has a dedicated pipeline connection pool (#4002). This includes failover clients and cluster node clients. Pipeline, TxPipeline, and autopipeline operations use this pool, so they do not compete with regular commands for main-pool connections. The pool is for burst capacity only: it dials only when necessary, an unused pool holds zero connections, and if the pool is full an operation uses the main pool. Set PipelinePoolSize: -1 to get the previous single-pool behavior.AutoPipelineOptions.MaxBatchBytes has a default of 128 KiB (before, there was no limit). The default prevents a write/reply deadlock; it is not a throughput control. The buffers of the pipeline pool also have a default of 128 KiB.⚠️ Changes to experimental APIs since 9.23.0-beta.1 (no effect if you upgrade from 9.22.0):
AutoPipelineOptions.FullDuplexFastSubmit is removed (#4018). The submit channel is replaced by a queue that takes a full wave of commands in one lock, so the separate fast path is not necessary. Remove the field from your options.Options.ClientSideCacheRefreshRecencyWindow is removed (#4034). Refresh-on-invalidate now reads again every cached entry of an invalidated key and does not look at how recently the entry was read. On a write-heavy keyspace this means refresh traffic across the full resident cache. Remove the field from your options.LocalCache.LRUClock() is removed (#4034). It returned the recency token that the removed recency window used, and has no replacement. Remove calls to it.ClientSideCacheInvalidationBatchWindow served stale values in beta.1 (#4033). Under load the batcher applied only ~15% of invalidations, and the cache served invalidated values with a ~100% hit rate. 9.23.0 applies all of them. If you used this option on beta.1, upgrade.Set AutoPipelineOptions.FullDuplex to enable the full-duplex mode of the automatic pipeliner. The default mode sends one batch per round trip. In full-duplex mode the engine holds one pipeline-pool connection, and a writer goroutine and a reader goroutine move the ordered command stream in both directions at the same time. On a high-latency link each command completes in approximately one round-trip time (RTT) on a single connection. On a 50 ms WAN profile: ~389k ops/s at 52 ms p50, against ~207k ops/s at 116 ms on the half-duplex ordered path.
The mode works on both faces of a standalone Client (AutoPipeline() and AsyncAutoPipeline()), and natively on a ClusterClient when routing goes to masters only. On a cluster, one child engine per master sends each command to the node that owns its slot, and follows MOVED / ASK redirects and retryable replies (LOADING, READONLY, ...) through the usual cluster redirect path. With replica routing (ReadOnly, RouteByLatency, or RouteRandomly), the autopipeliner uses the half-duplex shard flushers, which obey the shard picker. Config().FullDuplex reports the mode in effect.
Options:
FullDuplexWindow — the maximum number of commands in flight (backpressure).FullDuplexIdleTimeout and FullDuplexMaxHold — when the engine returns the held connection to the pool. The pool hooks then do re-authentication and maintenance-notification handoffs.MaxFlushDelay — now also used in full-duplex mode (#4014). The writer waits only when enough commands are in flight, so low-concurrency callers keep the 1×RTT behavior. With MaxFlushDelay=250µs at 1024 callers: +22% ops/s and −26% p99. The default is 0, so this is opt-in.NumShards — on a standalone Client, the number of full-duplex engines (#4022). See below.Pipeline() on the full-duplex connection (#4021). Standalone Client only. Before, ap.Pipeline() used a pooled connection for each Exec. It now submits the batch to the engine as one contiguous run (FDPipelined), so replies come back in submit order, as on a dedicated connection. At 256–1024 callers with 10 commands per Exec: +49% to +52% throughput on one socket instead of ~150. Errors, retries, hooks, and metrics behave like an ordinary pipeline. A batch that cannot use the stream (a blocking command, a per-command read timeout, a diverted command, or a batch larger than the queue) falls back to the ordinary pipeline. TxPipeline stays on a pooled connection, because MULTI/EXEC needs connection affinity. On a ClusterClient, ap.Pipeline() is still the ordinary cluster pipeline. A batch that the queue cannot admit now reserves its slots and waits in a first-come line, so single commands cannot starve a long pipeline (#4057, merged as part of #4021) by @vlady-kotsev.
Several engines on one client (#4022). With FullDuplex, NumShards > 1 now means N engines on one client: one pool, one hook chain, N held connections. Commands route by a hash of their first key, so commands on the same key stay on one connection and keep their order without Unordered. Keyless commands are distributed round-robin. An FDPipelined batch stays on one engine. The pipeline pool must hold at least NumShards connections for each full-duplex autopipeliner. More engines help only under high concurrency: with 10-command pipelines, 8 engines were 30% slower than 1 at 8 callers, equal at about 128 callers, and 2.2× faster at 1024 callers.
The full-duplex path supports blocking commands, Options.Limiter (one admission per written batch), per-command and pipeline hooks, OTel metrics, retry budgets (a NoRetry command is never sent again after it is on the wire), and seamless maintenance handoffs. Limits of the stream model:
ProcessHook that returns without calling next does not cancel the command on the full-duplex path; the command is already queued on the held connection. Run policy or kill-switch hooks on a plain client or on the half-duplex autopipeliner.HIMPORT commands. On the async face, wait for the result of a diverted command before you submit a command that depends on it.rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
AutoPipelineOptions: &redis.AutoPipelineOptions{
FullDuplex: true, // stream commands on one held connection, ~1 RTT each
},
})
defer rdb.Close()
// Deferred face: calls return immediately; result accessors block until executed.
ap, err := rdb.AsyncAutoPipeline()
if err != nil {
panic(err)
}
cmds := make([]*redis.StatusCmd, 0, 1000)
for i := 0; i < 1000; i++ {
cmds = append(cmds, ap.Set(ctx, fmt.Sprintf("key:%d", i), i, 0))
}
for _, cmd := range cmds {
if err := cmd.Err(); err != nil {
// handle error
}
}
// Or the blocking face — a drop-in Cmdable where each call blocks like a
// plain client while concurrent callers share the full-duplex pipe:
// ap, err := rdb.AutoPipeline()
// val, err := ap.Get(ctx, "key").Result()Runnable examples: example/autopipeline (all faces), example/autopipeline-fullduplex (blocking face, Pipeline() and FDPipelined), and example/autopipeline-fullduplex-async (async face, Submit, NumShards) (#4061).
Experimental: the auto-pipelining APIs can change in a minor release.
(#4002, #4014, #4018, #4021, #4022) by @ndyakov
Two new functions for the experimental shared-tracking client-side cache. They have no effect unless CSC is enabled (#3989) by @ndyakov:
Options.ClientSideCacheRefreshOnInvalidate): when an invalidation push arrives, the client reads every cached entry of that key again in the background, so the next reader does not pay the miss. Each invalidation of a cached key costs one background read. ClientSideCacheInvalidationBatchWindow collects invalidation-driven deletes into background batches; without it, the connection reader applies each delete inline.Options.ClientSideCacheCoalesceMisses): concurrent cache misses are pipelined on one tracked connection. Each miss keeps its own per-key command (no rewrite to MGET), so it is safe on a cluster. Each reply is written to the cache with the connection's tracking generation, so the server can invalidate it.Both options need the built-in cache (ClientSideCacheConfig, or ClientSideCache set to a *LocalCache). With a custom Cache implementation they are ignored.
The cache read path is also faster (#4034, #4035, #4036, #4037) by @ndyakov. A hit no longer writes a timestamp to the entry; a second-chance bit marks reads, and is set only under eviction pressure. The cache key is built in pooled scratch memory, the key list is built only on a miss, and nil/status/bulk-string hits are decoded without allocation. Against 9.23.0-beta.1 on a warm cache: +18% to +57% reads/s from 4 to 1024 callers, p50 from 2.6–5.4 µs to 1.0–1.5 µs, with identical hit rates and 100% of invalidations applied.
RouteByLatency selects the node with the strictly minimum latency. The measurement has noise (the mean of ten pings, refreshed at most every 10 s), so all clients can select the same node from a set of nodes with almost equal latency. In one production system, GET rates across five replicas in one availability zone had a 590× spread.
The new ClusterOptions.RouteByLatencyTolerance widens the selection to every node within the tolerance of the fastest node, and distributes reads across them round-robin with the ShardPicker. A node in a different availability zone stays outside a sensible tolerance, so zone locality is kept. The default is zero (strict minimum). The option is also on FailoverOptions, for clients from NewFailoverClusterClient; the plain NewFailoverClient does not support latency routing. (#3973) by @jozenstar
The same work fixed a routing defect: the client recorded the nearest healthy node only when that node was also the fastest overall. A node that fails fast (for example, a refused connection) hid every healthy node, and reads went to the failing node. The client now records the healthy minimum separately. (#3994) by @jozenstar
EphemeralConn for Session-Scoped WorkClient.Conn() returns its connection to the parent pool on Close. If you ran AUTH or SELECT on it, later commands on the pooled client run as that ACL user and in that DB. The new Client.EphemeralConn() returns the same sticky connection, but Close removes it from the pool instead. The cost is one dial per EphemeralConn. Client.Conn() is unchanged. (#4039) by @saddamr3e
AutoPipelineOptions.FullDuplex, with FullDuplexWindow / FullDuplexIdleTimeout / FullDuplexMaxHold, on standalone and cluster clients (#4002) by @ndyakovPipeline() on the full-duplex connection: ap.Pipeline() and FDPipelined submit a batch to the engine as one contiguous run, on a standalone Client (#4021) by @ndyakovNumShards > 1 with FullDuplex on a standalone Client, with key-hash routing (#4022) by @ndyakovAutoPipelineOptions.MaxQueuedCommands: an opt-in hard limit on accepted, not-yet-completed autopipeline commands. At the limit a command fails immediately with ErrAutoPipelineQueueFull, so memory does not grow without limit when the server is slow. With FullDuplex, the ordered stream is bounded by FullDuplexWindow instead (a full window blocks the submitter, it does not reject), and MaxQueuedCommands limits only the commands that run outside the stream (blocking, connection-hostile, Do). The default 0 means no limit (#4070) by @ndyakovPipelinePoolSize has a default of DefaultPipelinePoolSize (10) on each client. If the pool is full, an operation uses the main pool. Set -1 to disable the pool (#4002, #3959) by @ndyakovOptions.ClientSideCacheRefreshOnInvalidate (with ClientSideCacheInvalidationBatchWindow) and Options.ClientSideCacheCoalesceMisses (#3989) by @ndyakovClient.EphemeralConn: a sticky connection that is removed from the pool on Close, for session-scoped AUTH / SELECT work (#4039) by @saddamr3eRouteByLatencyTolerance: distributes reads across nodes with almost equal latency, on cluster clients and on NewFailoverClusterClient (#3973) by @jozenstarAutoPipeliner.WaitClosed: blocks until the drain of accepted commands completes, and returns the drain result. Use it in a wrapper that must not close shared pools during a flush (#3998) by @ndyakovredisotel-native WithRecordNilErrors: opt in to count redis.Nil replies as client errors (see the fix below) (#4025) by @lazergCMSInfo.CellSize: the cell-size field of CMS.INFO in Redis 8.12 (#4010) by @elena-kolevskaClientSideCacheInvalidationBatchWindow applied only ~15% of invalidations under load, so the cache served stale values with a ~100% hit rate. Each batch now takes each shard lock once, and 100% of invalidations are applied (#4033) by @ndyakovPut did not wake a worker that waited for a connection to become IDLE, so a streaming-credentials re-auth could stall until PoolTimeout and then close the connection (#4028) by @avitenzer. Two related waiter-queue races are fixed: a failed transition left a dead waiter queued, which later moved a connection to UNUSABLE for nobody (#4072) by @ndyakovBitOp*, MIGRATE, OBJECT ENCODING/FREQ/IDLETIME/REFCOUNT, XINFO STREAM/GROUPS/CONSUMERS, LMPOP, BLMPOP, SINTERCARD, ZINTERCARD, ZMPOP, BZMPOP) routed by the wrong argument. On a Ring they went to the wrong shard; on a cluster they cost an extra MOVED round trip. A raw FCALL / FCALL_RO hashed the function name. All now route by their key (#4048) by @ndyakov. Raw XGROUP, ZUNION / ZINTER / ZDIFF, SDIFFCARD / SUNIONCARD, TS.NRANGE / TS.NREVRANGE, and HIMPORT SET forms are also fixed (#4022)PExpireAt, HPExpireAt, and HPExpireAtWithArgs overflowed for dates outside the nanosecond range (for example, year 2270), so Redis deleted the key or rejected the command (#4026) by @jakezwang. SetArgs.ExpireAt now sends PXAT when the deadline has millisecond precision; before, EXAT dropped the milliseconds (#4053) by @LindseyZ1205-1 timeouts: a -1 read/write timeout on ClusterOptions gave node clients the 5 s default instead of no timeout (fixes #4049) (#4050) by @lazergredis.Nil as error: a cache miss (redis.Nil) incremented redis.client.errors and was tagged as a server error on db.client.operation.duration. Nil replies are now classified NIL and not counted, unless WithRecordNilErrors(true) is set (fixes #4024) (#4025) by @lazergSENTINEL SET ... auth-pass is now redacted in command rendering (used by redisotel / rediscensus span attributes), and a MIGRATE password with the literal value auth / auth2 is redacted at the correct position (#4011) by @saddamr3eAggMinAggregator / AggMaxAggregator panic instead of returning an error from Result() (#4056) by @SuselzParseURL skip_verify: an invalid value (for example, skip_verify=yes) was silently treated as false. ParseURL and ParseFailoverURL now return an error, like for the other boolean options (#4064) by @orinnzuintptr arguments: uintptr and *uintptr are now encoded like the other unsigned integers; a nil *uintptr is encoded as 0 (fixes #3100) (#4054) by @yamaankhan20*.INFO forward compatibility: the BF.INFO / CF.INFO / CMS.INFO / TOPK.INFO / TDIGEST.INFO parsers skip unknown fields instead of returning an error. Redis 8.12 adds cell size to CMS.INFO (#4010) by @elena-kolevskaNewClient panic leak: a panic during construction (for example, a maintnotifications failure in ModeEnabled) does not leak the connection pools that already exist, and a typed-nil pool cannot hide the initial panic (#4003) by @ndyakov. The same guards apply to NewFailoverClient (#4002)Conn.Close does the socket teardown and the unsubscribe/CSC callbacks when the connection is already CLOSED. Before, init and auth failures leaked open descriptors (fixes #3982) (#3985) by @ndyakovLogger and LogLevel, and call-site attribution is correct again (#3988) by @saddamr3eConn.onClose data race: the close hooks that init installs (onClose and onCscClose) are atomic against a concurrent Close (#3966) by @saddamr3eFTHybridCmd reads the full RESP3 map reply without desynchronizing the connection (#3956) by @saddamr3eCLIENT INFO forward compatibility: the parser skips unknown client-flag characters instead of failing the reply (#3977) by @ndyakovGEOSEARCH duplicate args: the command no longer sends duplicate arguments (#3955) by @mehmettokgozMSetEX cluster routing: the constructor sets the first-key position, so typed calls go to the correct slot (#3984) by @shivamrustagiClose: a concurrent Close does not block (no re-entrant deadlock), and WaitClosed returns the drain result (#3998) by @ndyakovisHealthyConn is logged only at debug level, so CSC invalidations do not fill the log (#3948) by @ndyakovPipeline / TxPipeline path removes the connection instead of returning a desynchronized connection to the pool (#4002) by @ndyakovMaxFlushDelay: opt-in write coalescing under load. With 250 µs at 1024–2048 callers: +22% to +25% ops/s and −26% to −29% p99; 30% less CPU at 256 callers (#4014) by @ndyakovScan gets zero-copy semantics, and the RESP reader skips unnecessary data conversions (#3972) by @vlady-kotsevgovulncheck dependency bumps: the minimum Go version is 1.26, CI defaults to 1.26, and a new go-versions job builds the test matrix from go.mod plus oldstable / stable (#4060) by @vlady-kotsevPing gate, which removes ~1.6 min of dial-retry waits when the full stack is not running (#4001) by @ndyakovCLIENT INFO tracking-flag assertion is skipped behind the RE proxy (#3981) by @ndyakovUniversalOptions documents ReadTimeout / WriteTimeout / ContextTimeoutEnabled (#4047) by @lazerg; the README describes DisableIdentity as client identification (CLIENT SETINFO), not identity verification (#4059) by @FanWu-aiWe thank all the contributors who worked on this release!
@avitenzer, @elena-kolevska, @FanWu-ai, @jakezwang, @jozenstar, @lazerg, @LindseyZ1205, @mehmettokgoz, @ndyakov, @orinnz, @Phalanyx, @saddamr3e, @shivamrustagi, @Suselz, @vlady-kotsev, @yamaankhan20
Full Changelog: v9.22.0...v9.23.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Security policy : send vulnerability reports to the Redis VDP ( #3949 ) by @ndyakov
This is a beta release. You can upgrade without changes to your code. The release adds three primary features:
The release also contains many stability fixes and robustness fixes.
⚠️ This release changes one default behavior. Each Client (this includes failover clients and cluster node clients) now creates a small, dedicated pipeline connection pool (#4002). Pipeline, TxPipeline, and autopipeline operations use this pool. These operations do not compete with regular commands for main-pool connections. The pool supplies burst capacity only:
Set PipelinePoolSize: -1 to get the previous single-pool behavior.
Set AutoPipelineOptions.FullDuplex to enable the full-duplex mode of the automatic pipeliner. The default mode sends one batch for each round trip. The full-duplex mode is different: the engine holds one pipeline-pool connection, and a writer goroutine and a reader goroutine move the ordered command stream in the two directions at the same time. On a link with high latency, each command completes in approximately one round-trip time (RTT) on a single connection. A test on a 50 ms WAN profile measured ~389k operations/s at 52 ms p50. The half-duplex ordered path measured ~207k operations/s at 116 ms.
The mode operates on the two faces of a standalone Client: AutoPipeline() and AsyncAutoPipeline(). The mode also operates natively on a ClusterClient if the routing goes to masters only. A child engine for each master sends each command to the node that owns the command's slot. The engine obeys MOVED and ASK redirects and retryable replies (LOADING, READONLY, ...) through the usual cluster redirect procedure. If replica routing is set (ReadOnly, RouteByLatency, or RouteRandomly), the autopipeliner uses the half-duplex shard flushers, which obey the shard picker. Config().FullDuplex reports the mode that is in effect.
These options tune the mode:
FullDuplexWindow — the maximum number of commands in flight (backpressure).FullDuplexIdleTimeout and FullDuplexMaxHold — control when the engine returns the held connection to the pool. The pool hooks then do the re-authentication and the maintenance-notification handoffs.FullDuplexFastSubmit — an optional fast submit path for many producers on low-RTT links.The full-duplex path supports blocking commands, Options.Limiter (one admission for each written batch), per-command hooks, OTel metrics, retry budgets (the client never sends a NoRetry command again after the command is on the wire), and seamless maintenance handoffs. The stream model causes these limits:
ProcessHook that returns without a call to next does not cancel the command on the full-duplex path. The command is already in the queue of the held connection, and the client sends it. Run policy hooks and kill-switch hooks on a plain client or on the half-duplex autopipeliner.HIMPORT commands. A diverted command has no order relation to the stream. On the async face, wait for the result of a diverted command before you submit a command that depends on it.rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
AutoPipelineOptions: &redis.AutoPipelineOptions{
FullDuplex: true, // stream commands on one held connection, ~1 RTT each
},
})
defer rdb.Close()
// Deferred face: calls return immediately; result accessors block until executed.
ap, err := rdb.AsyncAutoPipeline()
if err != nil {
panic(err)
}
cmds := make([]*redis.StatusCmd, 0, 1000)
for i := 0; i < 1000; i++ {
cmds = append(cmds, ap.Set(ctx, fmt.Sprintf("key:%d", i), i, 0))
}
for _, cmd := range cmds {
if err := cmd.Err(); err != nil {
// handle error
}
}
// Or the blocking face — a drop-in Cmdable where each call blocks like a
// plain client while concurrent callers share the full-duplex pipe:
// ap, err := rdb.AutoPipeline()
// val, err := ap.Get(ctx, "key").Result()The example/autopipeline directory contains a runnable tour of all the autopipeliner faces.
Two related defaults changed. AutoPipelineOptions.MaxBatchBytes now has a default of 128 KiB (before, the size had no limit). This default prevents a write/reply deadlock. It is not a throughput control. The buffers of the pipeline pool also have a default of 128 KiB.
Experimental: the auto-pipelining APIs can change in a minor release.
The release adds two functions to the experimental shared-tracking client-side cache. The functions have no effect unless CSC is enabled (#3989) by @ndyakov:
Options.ClientSideCacheRefreshOnInvalidate): the client reads recently-read keys again in the background immediately after their invalidation push arrives. The next reader does not pay the cache miss. The client collects invalidated hot keys in a short window and reads them again on a pipelined connection. ClientSideCacheRefreshRecencyWindow sets which entries count as recently read. ClientSideCacheInvalidationBatchWindow collects invalidation-driven cache deletes into background batches; without it, the connection reader applies each delete inline.Options.ClientSideCacheCoalesceMisses): the client pipelines concurrent cache-miss reads onto one tracked connection. Each miss keeps the caller's own per-key command. The client does not rewrite the commands to MGET, so the function is safe on a cluster. The client writes each reply to the cache with the tracking generation of the connection. The server can thus invalidate each entry.These options have the same requirement as the other CSC options: the built-in cache (ClientSideCacheConfig, or ClientSideCache set to a *LocalCache). The client ignores the options if a custom Cache implementation is set.
RouteByLatency selects the node with the strictly minimum latency. The latency measurement has noise: the value is the mean of ten pings, and the client refreshes it at most each 10 s. Thus all clients can select the same node from a set of nodes that have almost equal latency. A production system showed this problem: the GET rates across a five-replica set in one availability zone had a 590x spread.
The new ClusterOptions.RouteByLatencyTolerance widens the selection to each node with a latency in the tolerance above the fastest node. The client distributes reads across these nodes with the round-robin procedure of the ShardPicker. A node in a different availability zone stays outside a sensible tolerance, so zone locality is kept. The default is zero, which keeps the strict-minimum behavior. The option is also on FailoverOptions, where it applies to clients from NewFailoverClusterClient. The plain NewFailoverClient does not support latency routing. (#3973) by @jozenstar
The same work corrected a routing defect. The client recorded the nearest healthy node only when that node was also the fastest node overall. A node that fails fast (a refused connection fails fast, so this is frequent) thus hid each healthy node, and the client sent reads to the node that failed. The client now records the healthy minimum separately. (#3994) by @jozenstar
AutoPipelineOptions.FullDuplex, with FullDuplexWindow / FullDuplexIdleTimeout / FullDuplexMaxHold / FullDuplexFastSubmit. Available on standalone clients and cluster clients (#4002) by @ndyakovPipelinePoolSize has a default of DefaultPipelinePoolSize (10) on each client. If the pool is full, an operation immediately uses the main pool. Set -1 to disable the pool (#4002, #3959) by @ndyakovOptions.ClientSideCacheRefreshOnInvalidate (with ClientSideCacheRefreshRecencyWindow / ClientSideCacheInvalidationBatchWindow) and Options.ClientSideCacheCoalesceMisses (#3989) by @ndyakovRouteByLatencyTolerance: distributes reads across nodes that have almost equal latency, on cluster clients and on NewFailoverClusterClient (#3973) by @jozenstarAutoPipeliner.WaitClosed: blocks until the drain of the accepted commands completes, and returns the drain result. Use it in a wrapper that must not close shared pools while a flush is in progress (#3998) by @ndyakovCMSInfo.CellSize: contains the cell-size field of CMS.INFO in Redis 8.12 (#4010) by @elena-kolevska*.INFO forward compatibility: the parsers for BF.INFO / CF.INFO / CMS.INFO / TOPK.INFO / TDIGEST.INFO skip unknown fields and do not return an error. Redis 8.12 adds cell size to CMS.INFO (#4010) by @elena-kolevskaNewClient panic leak: a panic during construction (for example, a maintnotifications failure in ModeEnabled) does not leak the connection pools that already exist. A typed-nil pool cannot hide the initial panic (#4003) by @ndyakov. The same guards are applied to NewFailoverClient (#4002)Conn.Close does the socket teardown and the unsubscribe/CSC callbacks when the connection is already CLOSED. Before, init and auth failures collected open descriptors. The transport now closes exactly one time for each socket generation (fixes #3982) (#3985) by @ndyakovLogger and LogLevel. The call-site attribution is correct again (#3988) by @saddamr3eConn.onClose data race: the close hooks that init installs (onClose and onCscClose) are now atomic against a concurrent Close (#3966) by @saddamr3eFTHybridCmd reads the full RESP3 map reply and does not desynchronize the connection (#3956) by @saddamr3eCLIENT INFO forward compatibility: the parser skips unknown client-flag characters. The full reply does not fail (#3977) by @ndyakovGEOSEARCH duplicate args: the command does not send duplicate arguments (#3955) by @mehmettokgozMSetEX cluster routing: the constructor sets the first-key position. Typed calls thus go to the correct slot (#3984) by @shivamrustagiClose: a concurrent Close does not block (no re-entrant deadlock). WaitClosed supplies the drain result (#3998) by @ndyakovisHealthyConn shows only at the debug level. CSC invalidations do not fill the log (#3948) by @ndyakovPipeline/TxPipeline path (#4002) by @ndyakovScan gets zero-copy semantics, and the RESP reader does not do unnecessary data conversions (#3972) by @vlady-kotsevPing gate. This removes ~1.6 min of dial-retry waits in environments without the full stack (#4001) by @ndyakovCLIENT INFO tracking-flag assertion does not run behind the RE proxy (#3981) by @ndyakovWe thank all the contributors who worked on this release!
@elena-kolevska, @jozenstar, @mehmettokgoz, @ndyakov, @Phalanyx, @saddamr3e, @shivamrustagi, @vlady-kotsev
Full Changelog: v9.22.0...v9.23.0-beta.1
chore(release): release notes
chore(release): bump versions
chore(release): update release notes to ASD-STE100
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
One column per quarter.