Repository navigation
[Improvement] Wire the Pimcore cache pool to the Valkey container - #297
Conversation
docker-compose.yaml started a Redis container, but nothing used it: the pimcore.cache.pool block in config/config.yaml was commented out, so a fresh install silently ran Pimcore's object cache on the database adapter (cache_items table). - docker-compose.yaml: replace the redis service with valkey (same image, command and commented-out Redis alternative as demo-enterprise) so both packages use the same cache service. - .env: add REDIS_URL=redis://valkey:6379, like demo-enterprise. - config/config.yaml: enable the pimcore.cache.pool block with provider '%env(REDIS_URL)%'. - config/packages/test/config.yaml: use cache.adapter.array for tests (same as pimcore/pimcore's CI test config), so tests neither depend on the cache service nor share entries with the dev instance. - SkeletonProfile: add RedisEnvVarDefinition so the installer validates the cache connection during installation. - CI workflow: wait for valkey:6379 before running the installer. - README: mention Valkey and that the cache is pre-wired. Co-Authored-By: Claude <noreply@anthropic.com>
CI failed in "Run codeception tests" with: Service ".pimcore.cache.pool.inner": The argument "1" doesn't exist in class "Symfony\Component\Cache\Adapter\ArrayAdapter". Symfony merges pool options per pool name across config files, so in the test environment the array-adapter override still carried the provider '%env(REDIS_URL)%' from config/config.yaml. CachePoolPass maps provider to constructor argument 0 and default_lifetime to argument 1, but cache.adapter.array declares only one argument. Setting provider to null makes both FrameworkExtension and CachePoolPass treat the pool as having no provider (they check with isset), which puts default_lifetime back at argument 0, the same shape as pimcore/pimcore's CI test config. Co-Authored-By: Claude <noreply@anthropic.com>
The existing workflow proves the pool compiles, the installer can connect, and (via demo-enterprise) that reads work, but no step ever wrote to the cache: CLI processes do not write the object cache by default, and a web request flushes its save queue after the response is sent. pimcore:cache:warming uses forced writes, which bypass the CLI gate and go through RedisTagAwareAdapter::doSave, including its eviction-policy check. A fresh install has a root document, asset folder and object folder, so after warming, Valkey must hold keys; the step asserts DBSIZE > 0. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Test installation still validates Valkey connectivity despite using an in-memory cache.
1 open finding
What changed in this PR
Wires Pimcore’s object cache to Valkey instead of the database fallback.
Changes:
- Enables the cache pool through
REDIS_URLand adds installer validation. - Uses an in-memory cache for tests.
- Adds CI readiness and cache-write checks, plus setup documentation.
| File | Description |
|---|---|
src/Installer/SkeletonProfile.php |
Adds Redis connection validation. |
README.md |
Documents the preconfigured Valkey cache. |
docker-compose.yaml |
Replaces Redis with Valkey and fixes command arguments. |
config/packages/test/config.yaml |
Configures an isolated in-memory cache. |
config/config.yaml |
Enables the Redis-compatible cache pool. |
.github/workflows/pimcore-skeleton.yml |
Waits for Valkey and verifies cache writes. |
.env |
Sets the Valkey connection URL. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| new AmqpMessengerEnvVarDefinition(), | ||
| new MercureEnvVarDefinition(), | ||
| new ProductRegistrationEnvVarDefinition(), | ||
| new RedisEnvVarDefinition(), |
There was a problem hiding this comment.
Confirmed and fixed in a0446fe: added --skip-validation=redis to the test-install line, in line with the other services the test environment does not use (opensearch, messenger-amqp, mercure). The dev install still validates the Valkey connection, which is the point of adding the definition.
|
Have a look at the copilot finding and fix it, if necessary, Other than that it lgtm. |
The test environment uses cache.adapter.array, so the installer must not require a reachable Valkey there. The committed REDIS_URL activates the optional RedisEnvVarDefinition, whose validator opens a real connection regardless of APP_ENV, and `docker compose run test-php` does not start the valkey service. Skip it like the other services the test env does not use. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
CI note: the |
| command: [ valkey-server, --maxmemory, 128mb, --maxmemory-policy, volatile-lru, --save, '""' ] | ||
|
|
||
| # Valkey is a drop-in replacement for Redis. Comment out the valkey service | ||
| # above and uncomment the one below to use Redis instead. | ||
| # redis: | ||
| # image: redis:alpine | ||
| # command: [ redis-server, --maxmemory, 128mb, --maxmemory-policy, volatile-lru, --save, '""' ] |
There was a problem hiding this comment.
Checked against the Valkey source and the CI run; this is not an issue, no change needed.
The YAML '""' does pass the two-character string "" to valkey-server, but Valkey accepts it:
server.cmain()appends option arguments viasdscatrepr, so the config text becomessave "\"\"".config.cloadServerConfigFromString()splits that line toargv = [save, ""](the two-char value).saveis aMULTI_ARG_CONFIGwith exactly one non-empty argument, so the loader re-splits the value withsdssplitargs("\"\"")→ one empty token (config.c, "For MULTI_ARG_CONFIGs, if we only have one argument, try to split it by spaces").setConfigSaveOption()then hits its special caseargc == 1 && argv[0] == ""→resetServerSaveParams(), i.e. snapshots disabled. That is the same path asave ""line invalkey.conftakes.
Empirically: the green run on this PR (https://github.com/pimcore/skeleton/actions/runs/40677157135) started Valkey with exactly this command, dockerize -wait tcp://valkey:6379 succeeded, and the new CI step reported Keys in Valkey after cache warming: 7. demo-enterprise has run the identical line since July 2026 (pimcore/demo-enterprise#524). An empty '' would also work, but '""' is kept for consistency with demo-enterprise and the conf-file idiom.

Why
docker-compose.yamlstarted a Redis container, but nothing used it: thepimcore.cache.poolblock inconfig/config.yamlwas commented out, so a fresh install silently ran Pimcore's object cache on the database adapter (cache_itemstable). Core'sCacheFallbackPasspicks the DB adapter whenever no pool is defined; nothing readsREDIS_URLon its own.Follow-up to the discussion on pimcore/platform-version#615: fix it at the source instead of documenting the gap. Companion PR for demo-enterprise: pimcore/demo-enterprise#549.
Changes
docker-compose.yamlredis→valkey(valkey/valkey:alpine), same command and commented-out Redis alternative as demo-enterprise, so both packages use the same cache service. Also fixes the old command, which passed--maxmemory 128mbas a single argument..envREDIS_URL=redis://valkey:6379(same as demo-enterprise)config/config.yamlpimcore.cache.poolenabled withprovider: '%env(REDIS_URL)%'config/packages/test/config.yamlcache.adapter.arrayfor tests (same as pimcore/pimcore's CI test config): tests neither depend on the cache container nor share entries with the dev instancesrc/Installer/SkeletonProfile.phpRedisEnvVarDefinitionso the installer validates the cache connection.github/workflows/pimcore-skeleton.ymlvalkey:6379before running the installer;--skip-validation=redisfor the test installation, since the test env uses the array adapter anddocker compose run test-phpdoes not start ValkeyREADME.mdVerification
RedisEnvVarDefinitionexists in v2026.2.14+ and on 2026.x.provider: '%env(REDIS_URL)%'withredis_tag_awareis whatpaas-skeletonruns in production.compose up→ install → Codeception run and is the runtime check.pimcore:cache:warmingafter the install (forced writes go throughRedisTagAwareAdapter::doSave, including its eviction-policy check) and assertsvalkey-cli DBSIZE> 0. Without it no CI step ever writes to the cache: CLI processes don't write the object cache by default, and a web request flushes its save queue after the response is sent.Reviewer notes
REDIS_URLbecomes mandatory whereverconfig.yamlis loaded: a project without a reachable Redis/Valkey now fails to boot instead of silently using the DB. Intended, but a behaviour change for anyone copying the template to a non-Docker host.PdoSessionHandler).🤖 Generated with Claude Code
Part of pimcore/DevOps-Tasks#100