silverstripe / silverstripe-framework

Silverstripe Framework, the MVC framework that powers Silverstripe CMS

Home Page:https://www.silverstripe.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SPIKE: Investigate ways to get configurable cache adapter prior to loading config

GuySartorelli opened this issue · comments

#11145 points out a problem with APCu cache which is the current in-memory cache adapter. This is hard coded to be used if it's available, and not used if it's not.
Other cache adapters can be configured for many things, but the manifests will always use this default setup.

If we want to be able to configure the in-memory cache to be any arbitrary PSR6/PSR16 cache adapter, we need to be able to provide that configuration prior to booting the manifests. See BaseKernel::__construct().

Timebox

2 days

Spike objectives

  • Discover if there's a sensible way to provide configuration at a project-level for an in-memory cache adapter prior to booting manifests
  • If there is no sensible way to provide that configuration, consider what alternative options we might have to avoid the problems outlined in #11145

Some possible options Steve and I have already thought of:

  • If env variables are available at this stage, provide that config via env vars
    • Could be SS_IN_MEMORY_CACHE_CLASS which has some preset allowed values for memcached, redis, etc, along with SS_REDIS_SOMEARG1 etc, i.e. providing the data required for redis/memcached/etc to work
    • Could be SS_NO_MEMORY_CACHE so we either have one and it's there by default, or we don't have one. Doesn't solve everything but it's a half-way house to solving it
  • Could instantiate in project-level public/index.php and pass into the kernel
  • Use an explicit filesystem cache exclusively for dependency injection which is always built the same way in the same place
    • If that filesystem cache exists, use it to instantiate the dependency injector first, then build the cache adapter from it, boot manifests, and continue from there.
    • If that filesystem cache doesn't exist (or we're flushing), boot manifests so we can read regular config, and once the dependency injector config is all available, warm that filesystem cache for the next request
    • This is similar to how symfony does it - see Kernel::initializeContainer()

Turns out there's already a SS_MANIFESTCACHE environment variable to handle this. You set that to the FQCN for the class to use (either a PSR compliant cache adapter or a class that implements the CacheFactory interface).

In practice you'd probably have to use a factory, so you can use additional env vars to configure it.

So you'd probably have a MyCustomCacheFactory extends CacheFactory, and then you'd use that both with SS_MANIFESTCACHE and in yaml replacing the DefaultCacheFactory.

It's a bit crumby though - a single yaml config would be better so you don't have to remember to set the env var for it. I'll keep digging to see if there's something else we can do. For now though that's a good fallback position.

Looks like the env variable is the way to go - I played around with some other ideas but nothing really panned out. Closest I got was with the idea of caching some amount of the injector config separately from the main config cache - but it got way too messy.