Magento 2.2.4 – Modifying Cache Configs via CLI or env.php with Opcache Enabled

cachemagento2

So controlling my cache from command line or modifying env.php doesn't seem to work. Going into admin showed them all as disabled. Enabling them however within admin worked fine and shows all enabled from command line, env.php and within admin. Modifying them on command line however does nothing but modify env.php and make you think its enabled. What is going on!?

When i disable my opcache the issue stops happening and breaks when I enable. I have to flush my opcache everytime for the changes in the cache to become active but only when configuring cache via CLI or direct changes to env.php. Opcache seems to be caching these configs now it seems?

For now I have blacklisted env.php from opcache however am nervous that more issues may arise here as have never had to do this before.

Steps I have taken

  1. bin/magento cache:status shows all caches set to 1.
  2. Checked env.php, this has updated fine
  3. Reset permissions as per dev docs
  4. I can't find any instances of cacheable="false" within theme or modules
  5. No errors show in logs
  6. Checked redis which seems to be working however hard to debug the database being being used.
  7. Disabled all custom modules.
  8. Wanted to disable theme however new bug in 2.2.4 is stopping this (have renamed to bak majority of folders within theme for now)
  9. Restored a database backup
  10. …Asked a question on here.
  11. Stuck a bounty on it.

Cache:enable process

I have tried tracing what is actually going on when i run this command and so far I can see that the following happens:

Defined in Magento\Backend\Console\Command which extends AbstractCacheSetCommand

protected function configure()
{
    $this->setName('cache:enable');
    $this->setDescription('Enables cache type(s)');
    parent::configure();
}

This then sets enabled the applicable cache types:

$changedTypes = $this->cacheManager->setEnabled($types, $isEnable);

A few more steps through classes shows this command does the following:

public function setEnabled(array $types, $isEnabled)
{
    $changedStatusTypes = [];
    $isUpdated = false;
    foreach ($types as $type) {
        if ($this->cacheState->isEnabled($type) === $isEnabled) { // no need to poke it, if is not going to change
            continue;
        }
        $this->cacheState->setEnabled($type, $isEnabled);
        $isUpdated = true;
        $changedStatusTypes[] = $type;
    }
    if ($isUpdated) {
        $this->cacheState->persist();
    }
    return $changedStatusTypes;
}

However the following line leads me too and interface and am unable to determine the exact contents of that method:

$this->cacheState->setEnabled($type, $isEnabled);

This then runs below code:

public function setEnabled($cacheType, $isEnabled)
{
    $this->load();
    $this->statuses[$cacheType] = (int)$isEnabled;
}

And as Marius points out the persist function is what actually updates env.php.

public function persist()
{
    $this->load();
    $this->writer->saveConfig([ConfigFilePool::APP_ENV => [self::CACHE_KEY => $this->statuses]]);
}

This all seems to work correctly however will leave here as may help any future debugging. However in my situation env.php updates fine and this seems to be where cache configs should be read from, however i have discovered they seem to be cached in opache for some reason.

Best Answer

Picking up from where you got stuck....
the implementation of the interface StateInterface is Magento\Framework\App\Cache\State.

method setEnabled looks like this:

public function setEnabled($cacheType, $isEnabled)
{
    $this->load();
    $this->statuses[$cacheType] = (int)$isEnabled;
}

This is in a default install. If you have other custom modules that use a different implementation for the Cache states interface maybe you should look in there.

Moving on to the persist method...
It should be in the same class

public function persist()
{
    $this->load();
    $this->writer->saveConfig([ConfigFilePool::APP_ENV => [self::CACHE_KEY => $this->statuses]]);
}

this is the actual method that should write in env.php.

You can easily test if when running the command you reach this method.
(use a simple var_dump, die for test purposes).

If you do not reach this code it means you are using a different implementation for this interface.
And you can check this easily by adding

echo get_class($this->cacheState);exit;

(or use xdebug and adding a breakpoint)
right before $this->cacheState->setEnabled($type, $isEnabled);

Related Topic