feat: move Symfony sessions to Redis, env-configurable#440
Merged
Conversation
tuj
approved these changes
May 7, 2026
2784d94 to
e4abf91
Compare
framework.session.handler_id now reads from SESSION_HANDLER_DSN, which defaults to the existing REDIS_CACHE_DSN so dev (and prod that has Redis available) gets Redis-backed sessions out of the box. Operators can set SESSION_HANDLER_DSN= (empty) to fall back to PHP's native file handler. Why move: - Removes the per-session flock that serialises parallel session-touching requests on the file handler (visible as inconsistent tail latency when the React admin fires concurrent fetches). - Sessions survive container restarts without mounting /tmp as a volume. - Multi-pod deployments share session state without sticky routing — the OIDC handshake works regardless of which pod handles the callback. The new RedisSessionHandler is auto-built by Symfony from the DSN; it prefixes keys with `sf_s` so they don't collide with cache keys on the same Redis DB. when@test forces handler_id back to null, since MockFileSessionStorage doesn't go through a handler and we don't want the test container to compile a Redis handler against an env that may not point at a reachable Redis. Verified locally: HTTP request to /v2/authentication/oidc/urls writes a `sf_s<id>` key into Redis; full PHPUnit suite (143 tests, 607 assertions) passes with redis DBSIZE=0 after, confirming the test override works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e4abf91 to
b204a23
Compare
The previous rebase commit silently committed CHANGELOG.md with `<<<<<<<` / `=======` / `>>>>>>>` markers still in place — the Edit that resolved them lost a race against the git rebase tooling touching the same file, but `git add CHANGELOG.md` accepted the broken bytes and `git rebase --continue` succeeded. CI's markdownlint job (MD032) caught it. Both bullets are kept. Co-Authored-By: Claude Opus 4.7 (1M context) <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
framework.session.handler_idnow reads from a newSESSION_HANDLER_DSNenv var, which defaults to the existingREDIS_CACHE_DSN. Symfony's built-inSessionHandlerFactoryauto-creates aRedisSessionHandlerfrom theredis://...DSN — no service wiring or new dependencies. Operators can setSESSION_HANDLER_DSN=empty to fall back to PHP's native file handler.Why
flockthat serialises parallel session-touching requests on the file handler (visible as inconsistent tail latency when the React admin fires concurrent fetches)./tmpas a volume.Files Changed
config/packages/framework.yaml—handler_id: '%env(SESSION_HANDLER_DSN)%'in the global config;when@testforces it back tonullsinceMockFileSessionStoragebypasses handlers and we don't want the test container compiling a Redis handler against an env that may not point at a reachable Redis..env— addsSESSION_HANDLER_DSN=${REDIS_CACHE_DSN}with comment explaining the override path.CHANGELOG.md—[Unreleased]entry.Key isolation
The auto-built
RedisSessionHandlerprefixes keys withsf_s. Cache uses Symfony's owncache.adapter.redisprefix machinery driven byREDIS_CACHE_PREFIX=DisplayApiService. So sharing one Redis DB between cache and sessions is safe — keys don't collide. Operators wanting full DB separation can overrideSESSION_HANDLER_DSN=redis://redis:6379/1(or whatever DB).Local verification (already run)
docker compose run phpfpm bin/console debug:container session.handlerreports the handler is built viaSessionHandlerFactory::createHandler— Symfony's auto-build path for DSNs./v2/authentication/oidc/urls(the OIDC URL endpoint, which writes the session for state tracking) returns 200 and sets aPHPSESSIDcookie. Inspecting Redis post-request: exactly one key,sf_s<session-id>, matching the cookie.DBSIZE=0after the suite, confirming thewhen@testoverride keeps tests off Redis.Test Plan
docker compose down -v && docker compose up -d.curl -s -c /tmp/c.txt -o /dev/null -w '%{http_code}\n' http://nginx:8080/v2/authentication/oidc/urls?providerKey=internal→ expect200.docker compose exec redis redis-cli DBSIZE→ expect1(one newsf_s<id>key).SESSION_HANDLER_DSN= docker compose run --rm phpfpm bin/console debug:config framework session→ handler_id should resolve to empty/null and Symfony falls back to native file handler.docker compose run --rm phpfpm composer run test→ expect 143/143 green.🤖 Generated with Claude Code