feat(api): enable HTTP cache with Souin via FrankenPHP/Caddy#619
Merged
vincentchalamon merged 10 commits into4.3from Mar 31, 2026
Merged
feat(api): enable HTTP cache with Souin via FrankenPHP/Caddy#619vincentchalamon merged 10 commits into4.3from
vincentchalamon merged 10 commits into4.3from
Conversation
Compile Souin (RFC 7234 HTTP cache) + Otter (L1 in-memory) + Redis (L2 distributed) into the FrankenPHP binary. The cache is active in production only (controlled via CADDY_GLOBAL_OPTIONS and CADDY_SERVER_CACHE env vars) so the dev experience is unchanged. API Platform's SouinPurger handles automatic cache invalidation via surrogate keys on every write operation (only in prod, via config/packages/prod/api_platform.yaml). Add Redis service to Docker Compose and Helm chart to serve as the shared L2 cache store across pods. Document the decision in ADR #5. Closes #357 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…le lint Add a FaultTolerantSouinPurger decorator that catches transport exceptions thrown when the Caddy admin API (port 2019) is unreachable — this happens when running CLI commands such as doctrine:fixtures:load in a container that does not have FrankenPHP running (e.g. `docker compose run --rm php`). Also suppress Hadolint DL3062 on the go get line in the Dockerfile: using @latest is intentional to always pick up security patches in the builder stage, and pinning to a specific commit hash would make maintenance harder. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- readonly class removes implicit readonly on promoted properties - Rename catch variable $e to $throwable (CatchExceptionNameMatchingTypeRector) - Disable CADDY_SERVER_CACHE in compose.e2e.yaml: Souin would cache empty API responses during service startup (before fixtures load) and serve them as stale data during Playwright tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vincentchalamon
commented
Mar 31, 2026
vincentchalamon
commented
Mar 31, 2026
vincentchalamon
commented
Mar 31, 2026
vincentchalamon
commented
Mar 31, 2026
vincentchalamon
commented
Mar 31, 2026
- Replace sed-based main.go patching with an explicit frankenphp/main.go that declares all Caddy plugins: FrankenPHP, Mercure, Vulcain, Souin, Otter and Redis — making the binary composition fully transparent - Use when@prod syntax instead of config/packages/prod/ subdirectory - Add blank line before CACHE_INVALIDATION_URL in .env - Remove CADDY_SERVER_CACHE override from compose.override.yaml (useless in dev: compose.prod.yaml is required to activate Souin globally) - Upgrade Redis image from 7-alpine to 8-alpine Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace manual go build with xcaddy, the method recommended by the FrankenPHP documentation, so all Caddy plugins (FrankenPHP, Mercure, Vulcain, Souin, Otter, Redis) are declared explicitly via --with flags. Remove the hand-written main.go since xcaddy generates its own. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The frankenphp:1-builder image sets CGO_ENABLED=1 globally. xcaddy is a pure Go tool and fails to compile with CGO in this environment (runtime/cgo: unknown symbol stderr in pcrel). Explicitly disable CGO for the xcaddy install step; CGO_ENABLED=1 is still set for the actual FrankenPHP build. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
go install places binaries in $GOPATH/bin which is not in $PATH in the frankenphp builder image. Use $(go env GOPATH)/bin/xcaddy to invoke it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vincentchalamon
commented
Mar 31, 2026
Per review comment: the when@prod section must appear at the end of the file. Also fix indentation of defaults and oauth which belong under api_platform, not as direct keys of when@prod. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
293e589 to
8256f59
Compare
f57756e to
f9f4bc2
Compare
github.com/caddyserver/brotli does not exist. The correct module is github.com/dunglas/caddy-cbrotli, a CGO-based brotli implementation maintained by the FrankenPHP author, compatible with CGO_ENABLED=1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CADDY_GLOBAL_OPTIONS/CADDY_SERVER_CACHEenv vars — dev experience unchangedSouinPurgerhandles automatic surrogate-key invalidation on every write (prod only, viaconfig/packages/prod/api_platform.yaml)docs/adr/0005-http-cache-with-souin.mdTest plan
admin.api.souin,http.handlers.cache,storages.cache.otter,storages.cache.redis)Cache-Statusheader on responses (cache inactive)Cache-Status: Souin; fwd=uri-miss; storedCache-Status: Souin; hit; detail=OTTER(L1 hit)Closes #357
🤖 Generated with Claude Code