8000 Cache warmers are not run after clearing the cache in some scenarios · Issue #59445 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Cache warmers are not run after clearing the cache in some scenarios #59445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
javiereguiluz opened this issue Jan 9, 2025 · 8 comments
Closed

Comments

@javiereguiluz
Copy link
Member
javiereguiluz commented Jan 9, 2025

Symfony version(s) affected

All

Description

When the cache dirs don't exist (rm -fr var/cache/*) if you run the command bin/console cache:clear, Symfony runs cache warmers first and then deletes the entire cache (removing all the data created in the cache warmers).

If the cache dirs exist, Symfony does the right thing: first it clears the cache and then it runs the cache warmers.

Note: this is not a theoretical edge-case; this is impacting in real-world (see e.g. EasyCorp/EasyAdminBundle#6680)

How to reproduce

I created a small reproducer: https://github.com/javiereguiluz/reproducer

All the details are in the README

@MatTheCat
Copy link
Contributor
MatTheCat commented Jan 9, 2025

Just tried your reproducer, and while it’s true your cache warmer runs before the command, I ge 8000 t a Cache is fresh log in verbose mode and the cache directory is left untouched (optional warmers still run though). Is that not the case for you?

If I’m not mistaken such an issue would also impact the ConfigBuilderCacheWarmer 🤔

@filiplikavcan
Copy link
Contributor

I believe something called 'clear' should not perform a warmup.

I propose creating a new command, cache:purge, as a synonym for cache:clear --no-warmup. Alternatively, you might consider deprecating cache:clear or making --no-warmup the default option, though this would result in a breaking change.

@wouterj
Copy link
Member
wouterj commented Jan 11, 2025

@MatTheCat is correct.

In the first scenario (called "Error" in your reproducer):

  1. There is no cache, Symfony first warms up the cache as it needs this to run the cache:clear command
  2. The cache:clear command detects that the cache is warmed up seconds before and marks the cache as "fresh"
  3. When the cache is fresh, cache:clear skips clearing and warming up the cache ([FrameworkBundle] Remove double cache generation by detecting fresh kernels on cache:clear #26670)

This means that in that scenario, the "[OK] Cache for the "dev" environment (debug=true) was successfully cleared." message is incorrect: it didn't have to do anything and didn't do anything.

You can verify this works correctly by modifying the custom cache warmer a bit:

class CustomCacheWarmer implements CacheWarmerInterface
{
    public function warmUp(string $cacheDir, ?string $buildDir = null): array
    {
        echo "\033[30;44m[DEBUG]\033[0m Running my own custom cache warmer\n";

        file_put_contents($cacheDir.'/custom_run', 'Yes!');

        return [];
    }

    // ...
}

Despite only seeing the log message once, the custom_run file still exists in the cache directory after the command is finished.

@javiereguiluz
Copy link
Member Author
< 8000 /tr>

The code doesn't save things in the cache like this:

file_put_contents($cacheDir.'/custom_run', 'Yes!');

It uses Symfony's Cache via a custom cache pool:

->set('cache.easyadmin')
    ->parent('cache.system')
    ->tag('cache.pool')

And then something like this:

use Psr\Cache\CacheItemPoolInterface;

public function __construct(
    private CacheItemPoolInterface $cache,
) {
}

$routeNameToFqcnItem = $this->cache->getItem(self::CACHE_KEY_ROUTE_TO_FQCN);
$routeNameToFqcnItem->set($routeNameToFqcn);
$this->cache->save($routeNameToFqcnItem);

@MatTheCat
Copy link
Contributor
MatTheCat commented Jan 11, 2025

The cache item is removed by the Psr6CacheClearer when the CacheClearCommand runs $this->cacheClearer->clear($realCacheDir);.
Seems like non-optional cache warmers are not supposed to use the cache component. 🤔

@nicolas-grekas
Copy link
Member

#59581 should fix this issue.

But @javiereguiluz, please note that making the CacheWarmer of easy-admin non-optional is very likely a mistake. Proof is: this cache-warmer runs before the RouterCacheWarmer, which itself is optional.

nicolas-grekas added a commit that referenced this issue Jan 22, 2025
…s-grekas)

This PR was merged into the 6.4 branch.

Discussion
----------

[Cache] Don't clear system caches on `cache:clear`

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #59445
| License       | MIT

As spotted by `@MatTheCat` in #59445 (comment), non-optional cache warmers currently cannot use any cache pools derived from the `cache.system` one.

The reason is that when running `cache:clear` with no `var/cache` folder, we skip running those cache warmers since they already ran to execute the command, but we still call the cache clearer service, which empties system pools at the moment, annihilating anything non-optional cache warmers put in these pools.

I propose to fix this by just not clearing cache pools derived from the system pool anymore. System pools are meant to we stored in the `kernel.cache_dir` anyway, so they're already cleared when `cache:clear` empties that folder.

Commits
-------

8e82056 [Cache] Don't clear system caches on cache:clear
symfony-splitter pushed a commit to symfony/framework-bundle that referenced this issue Jan 22, 2025
…s-grekas)

This PR was merged into the 6.4 branch.

Discussion
----------

[Cache] Don't clear system caches on `cache:clear`

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #59445
| License       | MIT

As spotted by `@MatTheCat` in symfony/symfony#59445 (comment), non-optional cache warmers currently cannot use any cache pools derived from the `cache.system` one.

The reason is that when running `cache:clear` with no `var/cache` folder, we skip running those cache warmers since they already ran to execute the command, but we still call the cache clearer service, which empties system pools at the moment, annihilating anything non-optional cache warmers put in these pools.

I propose to fix this by just not clearing cache pools derived from the system pool anymore. System pools are meant to we stored in the `kernel.cache_dir` anyway, so they're already cleared when `cache:clear` empties that folder.

Commits
-------

8e820561295 [Cache] Don't clear system caches on cache:clear
@javiereguiluz
Copy link
Member Author

Thanks for looking into this. What would you recommend to fix this? Mark the cache warmer as optional? Extend the cache pool not from system but from app? I'm a bit lost here, sorry.

@nicolas-grekas
Copy link
Member
nicolas-grekas commented Jan 22, 2025

Mark it as non optional yes. This cache warmer is optional.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants
0