Add Redis queue storage driver#11
Conversation
b25b2a1 to
f116b1b
Compare
527287c to
9d4411a
Compare
f116b1b to
ebc2a9b
Compare
9d4411a to
43348f3
Compare
There was a problem hiding this comment.
Pull request overview
Adds a Redis-backed queue storage driver to the Cache Debounce module, allowing pending purge-tag dedupe and atomic claim/drain without relying on MySQL, and introduces a configurable driver-selection pool.
Changes:
- Introduces
Redis+Redis\ConnectionResolverimplementingQueueStorageInterfaceusing Redis sets + atomicRENAME. - Adds
Poolas theQueueStorageInterfacepreference, selectingdbvsredisviasamjuk_cache_debounce_advanced/general/storage_driver. - Adds unit + integration tests and updates admin/system config + ACL + README to support/configure the new driver.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Test/Unit/Model/Storage/RedisTest.php | Unit tests for Redis storage behavior (add/claim/tags/clear). |
| Test/Unit/Model/Storage/Redis/ConnectionResolverTest.php | Unit tests for dedicated vs fallback Redis connection resolution. |
| Test/Unit/Model/Storage/PoolTest.php | Unit tests for driver selection/caching behavior in the pool. |
| Test/Unit/Model/Config/Source/StorageDriverTest.php | Verifies storage driver option source exposes expected values. |
| Test/Integration/Model/Storage/RedisTest.php | Integration coverage for Redis round-trips and race scenarios. |
| Test/Integration/Model/Storage/Redis/ConnectionResolverTest.php | Integration coverage for dedicated/fallback Redis connection resolution. |
| README.md | Documents the storage driver config path and Redis env.php configuration. |
| Model/Storage/Redis/ConnectionResolver.php | Resolves Redis connection details from env.php with fallback to page_cache. |
| Model/Storage/Redis.php | Redis queue driver using SADD/RENAME/SMEMBERS/DEL. |
| Model/Storage/Pool.php | Driver selector implementing the storage interface and caching resolution. |
| Model/Config/Source/StorageDriver.php | Provides system.xml option source for driver selection. |
| etc/di.xml | Switches interface preference to Pool and registers driver map. |
| etc/config.xml | Adds default config value for advanced storage_driver. |
| etc/adminhtml/system.xml | Adds Advanced config section + storage driver select field. |
| etc/adminhtml/acl.xml | Adds ACL resource for the advanced storage driver config section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $this->client = $this->getMockBuilder(\Credis_Client::class) | ||
| ->disableOriginalConstructor() | ||
| ->addMethods(['sAdd', 'rename', 'sMembers', 'del']) | ||
| ->getMock(); |
There was a problem hiding this comment.
Claude: Not a real issue. Credis_Client dispatches sAdd/rename/sMembers/del via __call magic rather than declaring them as real methods, so addMethods() doesn't collide. CI is green across php74–php84, which confirms the mock builds fine. Fluff — skip.
| $config = $this->deploymentConfig->get(self::CONFIG_PATH_DEDICATED) ?: $this->resolveFallback(); | ||
|
|
||
| if (!$config) { | ||
| throw new LocalizedException(__( | ||
| 'SamJUK_CacheDebounce: no Redis connection could be resolved. Configure the ' | ||
| . '"cache_debounce.redis" block in app/etc/env.php, or configure a Redis backend ' | ||
| . 'for the "page_cache" cache frontend.' | ||
| )); | ||
| } | ||
|
|
||
| $this->client = new \Credis_Client( | ||
| $config['host'], | ||
| (int)$config['port'], | ||
| null, | ||
| '', | ||
| (int)$config['database'], | ||
| $config['password'] ?: null | ||
| ); |
There was a problem hiding this comment.
Claude: Confirmed, real gap. The fallback branch already defends missing keys with ?? defaults but the dedicated env.php branch doesn't — a config block missing e.g. password or database hits an undefined-index warning here. Cheap fix: mirror resolveFallback()'s null-coalescing pattern for the dedicated path.
| protected function setUp(): void | ||
| { | ||
| $reader = ObjectManager::getInstance()->get(DeploymentConfig\Reader::class); | ||
| $deploymentConfig = new DeploymentConfig($reader, ['cache_debounce' => ['redis' => self::CONNECTION_CONFIG]]); | ||
|
|
||
| $this->storage = new Redis(new ConnectionResolver($deploymentConfig)); | ||
|
|
||
| // A dedicated raw client, independent of the class under test, so | ||
| // cleanup can't be broken by the same bug it's meant to guard against. | ||
| $this->rawClient = new \Credis_Client( | ||
| self::CONNECTION_CONFIG['host'], | ||
| (int)self::CONNECTION_CONFIG['port'], | ||
| null, | ||
| '', | ||
| (int)self::CONNECTION_CONFIG['database'] | ||
| ); | ||
| $this->rawClient->flushDb(); | ||
| } |
There was a problem hiding this comment.
Claude: Confirmed, real risk, partially mitigated already — this uses Redis DB index 2 rather than 0, so it's not wiping the default DB. Still worth an explicit opt-in env var gate in case a dev's local Redis uses index 2 for something else.
| protected function setUp(): void | ||
| { | ||
| $this->reader = ObjectManager::getInstance()->get(DeploymentConfig\Reader::class); | ||
|
|
||
| (new \Credis_Client('127.0.0.1', 6379, null, '', self::DEDICATED_DATABASE))->flushDb(); | ||
| (new \Credis_Client('127.0.0.1', 6379, null, '', self::FALLBACK_DATABASE))->flushDb(); | ||
| } |
There was a problem hiding this comment.
Claude: Same as the sibling RedisTest comment — real risk, same fix (opt-in env var gate before allowing destructive flushDb calls in this test).
|
Claude: Overall — good driver implementation, three things worth resolving before merge: (1) ConnectionResolver needs null-coalescing on the dedicated env.php config keys, same as the fallback branch already has; (2) the storage_driver Admin UI visibility contradicts the README's CLI-only claim — default Administrator role has full ACL access so it will show up, needs a decision either way; (3) both Redis integration test suites do destructive flushDb() with no opt-in gate — low risk since they use non-default DB indices, but worth gating explicitly. The MockBuilder addMethods comment is fluff, CI already proves it's fine. |
30b71be to
ef94f80
Compare
f47df6d to
e8872c0
Compare
523d0a8 to
01b2871
Compare
e8872c0 to
9fdf93d
Compare
01b2871 to
35709d9
Compare
9fdf93d to
7c1f22a
Compare
35709d9 to
d871903
Compare
7c1f22a to
b932ccf
Compare
9255ab1 to
8ee2c3a
Compare
|
b932ccf to
ad5a3df
Compare
8ee2c3a to
60d514d
Compare
Redis implementation of QueueStorageInterface (SADD/RENAME/SMEMBERS/DEL, SUNIONSTORE for release), resolved via a Pool that picks db vs redis from samjuk_cache_debounce_advanced/general/storage_driver. That field is CLI-only: hidden from Admin UI (showInDefault/Website/Store all "0") and gated behind its own ACL resource, since switching storage drivers is a deploy-time infra decision, not a store setting. ConnectionResolver reads a dedicated app/etc/env.php block first, falling back to whatever Redis backend the page_cache frontend already uses so it works zero-config once switched on. Missing keys in either config fall back to sane defaults instead of hitting an undefined-index notice. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ad5a3df to
8d9da1f
Compare
60d514d to
368869f
Compare


Summary
Redisimplementation ofQueueStorageInterface(SADD/atomicRENAME/SMEMBERS/DEL), giving native dedupe and the same atomic claim/drain guarantee as the DB driver, without touching MySQL.cache_debounce.redisenv.php block, falling back to the existingpage_cacheRedis backend if absent (with a loud warning about that instance's eviction policy potentially dropping pending tags silently).Providerdecorator bound once indi.xml, switched via a scoped config value (storage_driver) that has nosystem.xmlfield — set only viaconfig:set, never Admin-visible, no per-driverdi.xmloverride module needed.Test plan
vendor/bin/phpunit Test/Unitpasses (verified against a real Magento install's classes, including the Credis mock-destructor edge case)vendor/bin/phpstan analyseclean at the repo's configured leveldev/tests/integrationagainst the CI Redis serviceconfig:set samjuk_cache_debounce/general/storage_driver redisswitches the driver and the field doesn't appear in Stores > Configuration