Skip to content

[13.x] Add cluster_aware Redis mode for managed single-endpoint providers#59797

Closed
timmylindh wants to merge 0 commit into
laravel:13.xfrom
timmylindh:feature/redis-serverless
Closed

[13.x] Add cluster_aware Redis mode for managed single-endpoint providers#59797
timmylindh wants to merge 0 commit into
laravel:13.xfrom
timmylindh:feature/redis-serverless

Conversation

@timmylindh
Copy link
Copy Markdown
Contributor

@timmylindh timmylindh commented Apr 21, 2026

Several managed Redis providers - AWS ElastiCache Serverless (Valkey), Upstash Redis, Redis Cloud with the DMC proxy - present a Redis Cluster behind a single endpoint while blocking the CLUSTER topology commands, so the client can't configure itself as a real cluster client. The endpoint still enforces slot semantics: multi-key commands return CROSSSLOT unless every key hashes to the same slot.

Laravel breaks out of the box on these providers. Cache::many(), Cache::putMany(), tagged cache flush(), and every queue push / pop / later / migrate script issue multi-key commands with no slot guarantee.

The existing hash-tag handling from #59533 only fires for real cluster clients - but here the client is standalone and only the server is clustered. There's no runtime signal to detect this, so the signal has to come from config.

This PR introduces a cluster_aware flag, opt-in per connection:

// config/database.php
'redis' => [
    'default' => [
        // ...
        'cluster_aware' => true,
    ],
],

When set, queue and limiter keys get hash-tagged, and multi-key cache operations fall back to per-key paths.

Changes

Connection infrastructure

  • Added isClusterAware() - true for real cluster clients or standalone connections with cluster_aware: true.
  • Added supportsMultiSlotMultiKeyCommands() - false when the client can't route a multi-key command across slots. Overridden to true on PhpRedisClusterConnection, which routes MGET/DEL/etc. per slot natively.
  • $config moved to the base Connection so PredisConnection can read it; Predis constructor and connector updated accordingly (BC-safe default).

RedisQueue & ConcurrencyLimiter

  • Keys are hash-tagged whenever isClusterAware() is true, not just for real cluster clients.

RedisStore

  • many() falls back to per-key get when ! supportsMultiSlotMultiKeyCommands(); phpredis cluster keeps the native MGET path.
  • putMany() falls back to per-key setex when isClusterAware() - MULTI/EXEC can't span slots on any cluster-like endpoint.

RedisTaggedCache

  • flush() uses the per-slot fallback when isClusterAware().
  • flushValues() uses pipelined per-key DEL when ! supportsMultiSlotMultiKeyCommands(); phpredis cluster keeps the variadic DEL fast path.

Backward Compatibility

  • cluster_aware defaults to false. Zero behaviour change for any existing config.
  • isCluster() semantics are unchanged - still true only for real cluster clients.
  • Real cluster connections return true from isClusterAware() via the isCluster() branch, so every rewired call site takes the same path it did before for them.
  • PredisConnection::__construct($client) still works; the new $config parameter is optional.

@github-actions
Copy link
Copy Markdown

Thanks for submitting a PR!

Note that draft PRs are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

@timmylindh timmylindh closed this Apr 22, 2026
@timmylindh timmylindh force-pushed the feature/redis-serverless branch from bd01dca to 79d24c8 Compare April 22, 2026 00:17
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.

1 participant