Skip to content
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

Cache is not correctly shared between CLI and non-CLI #11145

Closed
10 tasks done
GuySartorelli opened this issue Feb 16, 2024 · 6 comments
Closed
10 tasks done

Cache is not correctly shared between CLI and non-CLI #11145

GuySartorelli opened this issue Feb 16, 2024 · 6 comments

Comments

@GuySartorelli
Copy link
Member

GuySartorelli commented Feb 16, 2024

Module version(s) affected

Probably all of 'em, but I've only checked CMS 5 so far

Description

Cache run in the CLI with the PHP ini value apc.enable_cli NOT set to true will result in different cache being used compared with non-CLI or CLI with apc.enable_cli set to true.

This can result in cache being out of sync when values are changed in one context but not in the other.

There are two causes:

  1. The main one is that APCu isn't used in CLI, which means that cache doesn't get warmed or flushed by CLI actions
  2. The other is that the CLI context uses PhpFilesAdapter, but the non-CLI context falls back to FilesystemAdapter explicitly - so they're not even sharing filesystem-level cache.

UPDATE

It turns out APCu cache just can't be warmed or cleared from the CLI.
You can make curl or similar requests to the server form CLI to warm or clear the webserver APCu cache but that is kinda hacky and has some obvious drawbacks.

As I've noted in a comment below I've heard some people saying redis doesn't have this problem - it might make sense to provide support for redis in core with APCu as a fallback. At the very least we should clearly document this known and common problem with the current setup.

How to reproduce

  1. Set some config (any config) and run a flush in CLI, then load your app in the browser.
  2. Change the config value (note this only happens when changing existing config, not setting new config) and flush in the CLI only.
  3. Check /dev/config in the browser, and compare with sake dev/config in the CLI. You should see the old value in the browser, and the new value in the CLI.

Possible Solution

The second cause can be fixed right away by just using PhpFilesAdapter as the fallback in both contexts if it's supported, but the main problem needs to be fixed by Symfony. See symfony/symfony#53962

Additional Context

This is not talking about when running CLI with a different user or PHP version than the web server, which is a known and intentional distinction.

Validations

  • Check that there isn't already an issue that reports the same bug
  • Double check that your reproduction steps work in a fresh installation of silverstripe/installer (with any code examples you've provided)

OLD PRs

Notes

Acceptance criteria

  • APCu cache is no longer used as a default in CMS6
  • Both CLI and webserver use PhpFilesAdapter if available, or FilesystemAdapter otherwise
  • In-memory cache is available as an opt-in
  • There is a clearly documented configuration for opting in to using any given cache adapter
    • At a minimum, APCu, Redis, and Memcache are mentioned as options
  • Documentation calls out this limitation with ApcuAdapter when mentioning the ability to opt-in
  • The fact that in-memory cache is opt-in is mentioned somewhere in server requirements or getting started docs so people know early on in their development journey what to expect in that regard
    • This should link to the broader docs about cache, which is where the opt-in config will be documented
  • If feasible, framework CI tests against the following scenarios:
    • No in-memory cache configured
    • APCu in-memory cache configured
    • Memcached in-memory cache configured
    • Redis in-memory cache configured

Kitchen sink CI run: https://github.com/creative-commoners/recipe-kitchen-sink/actions/runs/9898902083

CI PRs

Main PRs

@GuySartorelli
Copy link
Member Author

GuySartorelli commented Feb 26, 2024

Turns out even enabling apc.enable_cli doesn't resolve this problem... so it might be that it's a fundamental restriction with APCu itself? If that's the case, best we can do is:

  1. Make sure out CLI and non-CLI are sharing the same filesystem cache
  2. Very clearly document that with APCu cache enabled, flushing from the CLI will not flush the browser cache

I've seen anecdotal reports that redis resolves this, so maybe we should highlight that a bit, too.

@GuySartorelli GuySartorelli removed their assignment Feb 26, 2024
@GuySartorelli GuySartorelli changed the title Cache is not correctly shared between CLI and non-CLI with apc.enable_cli !== true Cache is not correctly shared between CLI and non-CLI Mar 14, 2024
@elliot-sawyer
Copy link
Contributor

Chatting with @GuySartorelli on Slack:

I've done quite a bit of work on caching with https://github.com/pstaender/silverstripe-redis-cache and there's some good example config for forcing everything over into Redis if one was so inclined. One thing the module cannot do is force <% cached %> blocks into the cache. I still don't know where that content is stored, but I believe the class manifest is also written to the filesystem with PhpFilesAdapter

@forsdahl
Copy link
Contributor

In my experience, PhpFilesAdapter will not be used by default in CLI in any standard PHP configuration, but it will be used by default in non-CLI conditions (since it is dependent on OPcache being enabled). This means that even without APCu, there will still be a mismatch in cache-adapters between CLI and non-CLI. Internally we have started configuring PHP so that we enable OPCache for CLI, but with very specific configuration options (since enabling OPCache for CLI is not really recommended, and with the incorrect configuration it will actually be slower).
Our PHP configuration for CLI is to do the following configs:

opcache.enable_cli=1
opcache.blacklist_filename=/path/to/blacklist.txt
opcache.file_cache="/var/tmp/"
opcache.file_cache_only=1
opcache.file_cache_consistency_checks=1

That blacklist.txt file contains the path to the Silverstripe installation, so that in practice OPCache is not used at all in CLI, it is just configured to be enabled.
All in all a really cumbersome way to get around the problem, but I don't see any direct way of doing this easily, except for to perhaps warm the FilesystemAdapter cache from non-CLI even though that is not the one used (which might impact performance)?
Solving this would be good though, since there are a fair number of questions related to this on the Slack channel.

@GuySartorelli
Copy link
Member Author

Need to figure out how to get the in-memory cache configured before we have the manifests, since we need it to cache the config (and therefore can't put it in config)

See #11257

@GuySartorelli
Copy link
Member Author

GuySartorelli commented Jul 12, 2024

There's still an unmerged pr here

@GuySartorelli GuySartorelli reopened this Jul 12, 2024
@elliot-sawyer
Copy link
Contributor

#11300 makes me super happy, nice work team! 🎉

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

4 participants