Skip to content

feat: make the cache pool backend configurable with CACHE_ADAPTER#498

Merged
turegjorup merged 3 commits into
release/3.0.0from
feature/cache-adapter-env-config
Jun 23, 2026
Merged

feat: make the cache pool backend configurable with CACHE_ADAPTER#498
turegjorup merged 3 commits into
release/3.0.0from
feature/cache-adapter-env-config

Conversation

@turegjorup

Copy link
Copy Markdown
Contributor

Summary

The application cache pools (feeds.cache, feed.without.expire.cache, calendar.api.cache, auth.screen.cache, screen.status.cache, interactive_slide.cache) were hard-wired to cache.adapter.redis, forcing every installation to run Redis. This PR makes the backend selectable at runtime with a new CACHE_ADAPTER env var: redis (default, behavior unchanged), memcached, dbal, filesystem or apcu.

Why a factory instead of %env()% in cache.yaml

Symfony resolves a pool's adapter: option to a concrete service id at container compile time (CachePoolPass makes each pool a ChildDefinition of the adapter service), so the choice cannot be expressed with a runtime env placeholder. The pools now extend an abstract app.cache.adapter service backed by App\Cache\CacheAdapterFactory, which builds the selected adapter at runtime; CachePoolPass injects each pool's computed namespace and configured default_lifetime as the factory arguments. The custom parent mirrors the built-in cache.adapter.* wiring: lazy Redis/Memcached connections, pools attached to cache.default_clearer (wiped by cache:clear on deploy, as before) and reset: reset for long-running workers.

Backend notes

  • redis (default) — unchanged; still uses REDIS_CACHE_DSN.
  • memcached — shared like redis (MEMCACHED_CACHE_DSN, requires ext-memcached). Documented caveat: Memcached LRU-evicts under memory pressure, so long-lived entries (screen status, activation codes) can disappear early.
  • dbal — shared cache in the application database; the cache_items table is auto-created on first write. A schema_filter hides it from doctrine:migrations:diff / schema:validate. TTL is honored on read (expired rows are deleted when encountered).
  • filesystem — per-node under var/cache/<env>/pools; for single-server setups without Redis.
  • apcu — per-PHP-process-pool; not shared with console crons or across nodes.

All backends honor default_lifetime and per-item TTLs (PSR-6 contract); an unknown CACHE_ADAPTER value fails fast with a message listing the valid options. array was deliberately not offered: a per-request cache breaks the screen activation flow (auth.screen.cache).

Files Changed

  • src/Cache/CacheAdapterFactory.php (new) — runtime adapter factory
  • config/services.yaml — factory wiring + abstract app.cache.adapter parent
  • config/packages/cache.yaml — pools now extend app.cache.adapter
  • config/packages/doctrine.yamlschema_filter for cache_items
  • .envCACHE_ADAPTER + MEMCACHED_CACHE_DSN docs and defaults
  • .env.test + deleted config/packages/test/cache.yaml — tests run with CACHE_ADAPTER=filesystem instead of per-pool overrides, removing the implicit Redis dependency from the three pools the old override file didn't cover
  • tests/Cache/CacheAdapterFactoryTest.php (new) — unit tests incl. dbal roundtrip with table auto-creation (sqlite) and lazy redis/memcached creation
  • CHANGELOG.md — Unreleased entry

Test Plan

  • task test:api -- --filter CacheAdapterFactoryTest — 7 tests (APCu skipped where ext missing)
  • task test:api -- --filter AuthenticationScreenTest — screen auth flow through factory-built filesystem pools: green
  • Runtime switching on one compiled container: docker compose exec -e CACHE_ADAPTER=<redis|dbal|filesystem> phpfpm bin/console cache:pool:clear feeds.cache all succeed; -e CACHE_ADAPTER=bogus fails with Unknown CACHE_ADAPTER "bogus". Expected one of: "redis", "memcached", "dbal", "filesystem", "apcu".
  • task code-analysis, task rector:check, task coding-standards:check, scripts/check-env-coverage.sh — green
  • No API surface change (no src/Dto/src/State touched), so no spec regeneration needed

🤖 Generated with Claude Code

turegjorup and others added 2 commits June 11, 2026 19:24
The application cache pools (feeds, calendar, screen auth/status,
interactive slides) were hard-wired to cache.adapter.redis, forcing every
installation to run Redis. A pool's adapter must be a service id at
container compile time, so the backend cannot be switched with a runtime
%env()% placeholder; instead the pools now extend an abstract
app.cache.adapter service backed by App\Cache\CacheAdapterFactory, which
builds the adapter selected by the new CACHE_ADAPTER env var at runtime:
redis (default, unchanged), memcached, dbal (shared via the application
database, table auto-created), filesystem or apcu.

The factory mirrors the built-in adapter wiring: lazy connections, pools
cleared by cache:clear and reset in long-running workers. A schema_filter
hides the dbal adapter's cache_items table from the Doctrine schema tools.
Tests now run with CACHE_ADAPTER=filesystem instead of per-pool overrides,
removing the implicit Redis dependency from the three previously
unoverridden pools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The itkdev/php8.4-fpm images ship ext-apcu disabled (apc.enabled=0);
CACHE_ADAPTER=apcu needs PHP_APCU_ENABLED=1 and a suitable
PHP_APCU_MEMORY_SIZE set on the container.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@turegjorup turegjorup self-assigned this Jun 11, 2026
…e-adapter-env-config

# Conflicts:
#	CHANGELOG.md
@turegjorup
turegjorup merged commit 79e711a into release/3.0.0 Jun 23, 2026
24 checks passed
@turegjorup
turegjorup deleted the feature/cache-adapter-env-config branch June 23, 2026 10:20
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