Skip to content

Fix Redis unix socket connections in SymfonyAdapterProvider (silent filesystem fallback)#41001

Open
rhoerr wants to merge 1 commit into
magento:2.4-developfrom
rhoerr:fix/symfony-cache-redis-unix-socket
Open

Fix Redis unix socket connections in SymfonyAdapterProvider (silent filesystem fallback)#41001
rhoerr wants to merge 1 commit into
magento:2.4-developfrom
rhoerr:fix/symfony-cache-redis-unix-socket

Conversation

@rhoerr

@rhoerr rhoerr commented Jul 15, 2026

Copy link
Copy Markdown

Description (*)

Configuring the Redis cache backend with a unix socket in env.php ('backend' => 'redis', 'server' => '/path/to/redis.sock', 'port' => '0') silently falls back to the filesystem cache adapter — cache and FPC quietly stop using Redis with no error and no log entry.

Root cause: SymfonyAdapterProvider::createPhpRedisConnection() builds the DSN as redis://host:port/db unconditionally:

$baseDsn = $password
    ? sprintf('redis://%s@%s:%d/%d', urlencode($password), $host, $port, $database)
    : sprintf('redis://%s:%d/%d', $host, $port, $database);

With a socket config this yields redis:///path/to/redis.sock:0/1. Symfony's RedisTrait::createConnection() strips the trailing /1 as the dbindex and resolves the unix socket file as /path/to/redis.sock:0, which does not exist. The connection failure is swallowed by createAdapter()'s catch-all \Exception handler, which falls back to createFilesystemAdapter() without logging. The Predis fallback path (createOptimizedPredisConnection()) has the same gap — it always builds scheme => tcp parameters.

Fix: treat a host beginning with / as a unix socket path — the same convention used by phpredis's connect() and by Credis behind the previous Magento\Framework\Cache\Backend\Redis, so socket configurations that worked before the Symfony cache migration work again unchanged — and emit Symfony's documented socket DSN form redis://[auth@]/path/to/redis.sock/<dbindex>. The Predis parameter builder likewise emits scheme => unix, path => ... for socket hosts. A hostname can never begin with / (DNS labels are letters/digits/hyphens), so the check cannot misroute TCP configurations.

Minor related correction: the password is now rawurlencode()d rather than urlencode()d, matching the rawurldecode() Symfony applies when parsing DSN userinfo (differs only for passwords containing spaces).

DSN construction and Predis connection parameters are extracted into small private builder methods (buildRedisBaseDsn(), buildPredisConnectionParameters()) so they are unit-testable; behavior is otherwise unchanged.

Related Pull Requests

Same fix submitted to Mage-OS: mage-os/mageos-magento2#294

Fixed Issues (if relevant)

N/A (root cause analysis included above)

Manual testing scenarios (*)

  1. Configure Redis over a unix socket in app/etc/env.php for default and page_cache:
    'backend' => 'redis',
    'backend_options' => [
        'server' => '/var/run/redis/redis.sock',
        'port' => '0',
        'database' => '1',
    ],
  2. Flush cache, browse the storefront.
  3. Before the fix: redis-cli -s /var/run/redis/redis.sock -n 1 dbsize stays at 0 and var/cache/ fills with filesystem cache entries.
  4. After the fix: Redis dbsize grows, var/cache/ is no longer populated by the cache frontend.
  5. Regression check: TCP configurations ('server' => '127.0.0.1', 'port' => '6379'), with and without password, behave as before.

New unit test Magento\Framework\Cache\Test\Unit\Frontend\Adapter\SymfonyAdapterProviderTest covers TCP and socket DSN/parameter building, with/without auth, password encoding of reserved characters, and port being ignored for sockets (11 tests, 11 assertions, PHPUnit 12).

Questions or comments

The catch-all fallback in createAdapter() that swallows connection errors without logging turns any Redis misconfiguration into an invisible performance regression; a follow-up adding at least a log line may be worthwhile.

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • README.md files for modified modules are updated and included in the pull request if any README.md predefined sections require an update
  • All automated tests passed successfully (all builds are green)

Also submitted to Mage-OS 3: mage-os/mageos-magento2#294

The Symfony cache adapter builds Redis DSNs as redis://host:port/db.
When env.php configures a unix socket (server => /path/redis.sock,
port => 0), this produces redis:///path/redis.sock:0/1 - Symfony's
RedisTrait strips the trailing /1 as the dbindex and resolves the
socket file as 'redis.sock:0', which does not exist. The connection
failure is swallowed by createAdapter()'s catch-all, so cache and FPC
silently fall back to the filesystem adapter with no logging.

Treat a host beginning with '/' as a unix socket path - the same
convention phpredis and Credis (the previous Zend-based Redis backend)
use - and emit Symfony's socket DSN form:

  redis://[auth@]/path/to/redis.sock/<dbindex>

Apply the same handling to the Predis fallback connection parameters
(scheme unix + path instead of tcp + host/port). Passwords are now
rawurlencode()d instead of urlencode()d, matching the rawurldecode()
Symfony applies when parsing DSN userinfo.

DSN construction and Predis parameter building are extracted into
private builder methods with unit test coverage for TCP and socket
forms, with and without auth.

Signed-off-by: Ryan Hoerr <rhoerr@gmail.com>
@m2-assistant

m2-assistant Bot commented Jul 15, 2026

Copy link
Copy Markdown

Hi @rhoerr. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@ct-prd-pr-scan

Copy link
Copy Markdown

The security team has been informed about this pull request due to the presence of risky security keywords. For security vulnerability reports, please visit Adobe's vulnerability disclosure program on HackerOne or email psirt@adobe.com.

1 similar comment
@ct-prd-pr-scan

Copy link
Copy Markdown

The security team has been informed about this pull request due to the presence of risky security keywords. For security vulnerability reports, please visit Adobe's vulnerability disclosure program on HackerOne or email psirt@adobe.com.

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.

1 participant