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

FIX Ensure cache is shared between CLI and webserver #11300

Merged
merged 2 commits into from
Jul 12, 2024

Conversation

GuySartorelli
Copy link
Member

@GuySartorelli GuySartorelli commented Jul 4, 2024

Description

  • Removes default in-memory cache
  • Uses PhpFilesAdapter as the default filesystem cache adapter
  • Falls back on FilesystemAdapter only if PhpFilesAdapter isn't supported by both webserver and CLI
  • Adds new RedisCacheFactory as an option for in-memory cache
  • Adds new SS_MEMORY_CACHEFACTORY environment variable for opting in to in-memory cache
    • Has to be an environment variable because config isn't available when the manifest cache adapter is instantiated
  • Amends ApcuCacheFactory and MemcachedCacheFactory to use args passed into create() or environment variables instead of constructor args
  • Use symfony to build Memcached client instead of relying on injector (injector config isn't available early enough)
  • Strict typehinting for Factory::create() and its subclasses
  • Unit testing that validates the correct cache adapters are used, and that their logger is set correctly

There is an edge-case drawback to this approach.
All redis/memcached cache will always use the same connection details. You couldn't for example use one redis server to cache some stuff, and another server to cache some other stuff.
The workaround for that would be to implement your own CacheFactory class for instantiating the cache adapter for the stuff you want on another server. So we're not locking out that possibility, just requiring a little bit more boilerplate if people want to do that.

Requires

The following PRs need to be merged for CI to go green:

Issues

public function create($service, array $params = []);
public function create(string $service, array $params = []): ?object;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly necessary - but it does make things a bit clearer. Can remove this change if it's causing headaches.

Comment on lines +44 to 62
private function isSupported(): bool
{
static $isSupported = null;
if (null === $isSupported) {
// Need to check for CLI because Symfony won't: https://github.com/symfony/symfony/pull/25080
$isSupported = Director::is_cli()
? filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOL) && ApcuAdapter::isSupported()
: ApcuAdapter::isSupported();
}
return $isSupported;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is moved here from DefaultCacheFactory

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this class is moved here from DefaultCacheFactory

@@ -7,7 +7,6 @@ SilverStripe\Core\Injector\Injector:
constructor:
args:
directory: '`TEMP_PATH`'
version: null
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version is effectively a flush mechanism - if the version changes, all cache with the previous version is invalidated.

Given this config isn't available when instantiating manifest cache, I've moved this to being an environment variable. In practice I don't think anyone would ever bother setting it since Silverstripe CMS has so many ways to flush cache.

@GuySartorelli GuySartorelli force-pushed the pulls/6/in-memory-cache branch 2 times, most recently from c0e7664 to f8c11d8 Compare July 4, 2024 04:06
*/
public function create($service, array $params = []);
public function create(string $service, array $params = []): CacheInterface;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this is PSR16 - this is intended for direct use.

@GuySartorelli GuySartorelli force-pushed the pulls/6/in-memory-cache branch from f8c11d8 to 839cb92 Compare July 4, 2024 04:17
/**
* Create a PSR6-compliant cache adapter
*/
public function createPsr6(string $service, array $params = []): CacheItemPoolInterface;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PSR6 specifically required so it can be bundled in a ChainAdapter along-side the filesystem cache adapter.
This is in contrast to the create() method which must be PSR16 for direct use.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The YAML for these is no longer valid, and these tests would now fail if memcached isn't installed and apcu isn't enabled for CLI.

These are covered through the new DefaultCacheFactoryTest anyway.

@GuySartorelli GuySartorelli force-pushed the pulls/6/in-memory-cache branch from c75413f to feec1d2 Compare July 9, 2024 00:49
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes here are a natural consequence of strict typing in the Factory interface. It's documented in the changelog.

@GuySartorelli GuySartorelli force-pushed the pulls/6/in-memory-cache branch from feec1d2 to 2321737 Compare July 9, 2024 00:58
@GuySartorelli GuySartorelli marked this pull request as ready for review July 9, 2024 01:40
Comment on lines 15 to 20
phpunit_skip_suites: framework-cache-only
# Ensure we test all in-memory cache factories provided in core
extra_jobs: |
- phpunit: true
phpunit_suite: framework-cache-only
install_inmemory_cache_exts: true
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works with the two CI PRs to ensure we install everything we need to be able to include all three in-memory cache adapters in the new DefaultCacheFactoryTest test.

throw new RuntimeException('Redis is not supported in the current environment. Cannot use Redis cache.');
}

$dsn = Environment::getEnv('SS_REDIS_DSN');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth simply having SS_IN_MEMORY_CACHE_DSN and checking it starts with redis instead on splitting out SS_REDIS_DSN and SS_MEMCACHED_DSN, given that there's only a single SS_IN_MEMORY_CACHE_FACTORY?

Copy link
Member Author

@GuySartorelli GuySartorelli Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's cleaner if they're separate, given the factories are separate. Each factory looks for its own DSN. I wouldn't want the memcached factory to be looking for a DSN variable that's shared with Redis, that sounds messy to me.

.github/workflows/ci.yml Outdated Show resolved Hide resolved
src/Core/Cache/DefaultCacheFactory.php Outdated Show resolved Hide resolved
src/Core/Cache/DefaultCacheFactory.php Outdated Show resolved Hide resolved
tests/php/Core/Cache/DefaultCacheFactoryTest.php Outdated Show resolved Hide resolved
tests/php/Core/Cache/DefaultCacheFactoryTest.php Outdated Show resolved Hide resolved
tests/php/Core/Cache/DefaultCacheFactoryTest.php Outdated Show resolved Hide resolved
src/Core/Cache/DefaultCacheFactory.php Outdated Show resolved Hide resolved
@GuySartorelli GuySartorelli force-pushed the pulls/6/in-memory-cache branch from ed04e03 to ed321f8 Compare July 11, 2024 21:30
@emteknetnz emteknetnz merged commit 386ff5a into silverstripe:6 Jul 12, 2024
@emteknetnz emteknetnz deleted the pulls/6/in-memory-cache branch July 12, 2024 00:28
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.

2 participants