Add validation for cache bin service arguments

Created on 20 January 2017, over 8 years ago
Updated 23 January 2023, over 2 years ago

Problem/Motivation

When creating a cache.$bin_name service, documentation for the cache API implies (but does not assert) that the service arguments: should be set to [$bin_name].

However, nothing in the code enforces this, and it's entirely possible to configure a cache service with service name and bin name different e.g:

services:
  cache.foo:
    class: Drupal\Core\Cache\CacheBackendInterface
    tags:
      - { name: cache.bin, default_backend: cache.backend.memory }
    factory: cache_factory:get
    arguments: [foo_bar]

This service will register fine, and appear to work fine, but will suffer from undefined behaviour; for example, its default_backend will not be respected.

The problem can be demonstrated with the following class:

namespace Drupal\cacheproblem;
class CacheProblem {
    public function __construct(CacheBackendInterface $cacheBackend) {
    $this->cacheBackend = $cacheBackend;
  }

  public function test() {
    print "Previously:\tupdate=" . $this->cacheBackend->get('update') . "\n";

    $string = date('c');
    $this->cacheBackend->set('update', $string);
    print "Cached update:\t$string\n";

    print "Now set to:\tupdate=" . $this->cacheBackend->get('update') . "\n";
  }
}

With the correct memory backend, this should not remember cached values between requests i.e. all calls should be the same as the first one.

With cache.foo and arguments: [foo]

This response reflects the correct behaviour:

$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=
Cached update:	2017-01-20T15:30:18+00:00
Now set to:	update=2017-01-20T15:30:18+00:00
$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=
Cached update:	2017-01-20T15:30:23+00:00
Now set to:	update=2017-01-20T15:30:23+00:00
$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=
Cached update:	2017-01-20T15:30:28+00:00
Now set to:	update=2017-01-20T15:30:28+00:00

The cache never "warms up", because it's correctly in memory.

With cache.foo and arguments: [foo_bar]

This response reflects incorrect/undefined behaviour, when the first argument does not match the service name:

$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=
Cached update:	2017-01-20T15:29:34+00:00
Now set to:	update=2017-01-20T15:29:34+00:00
$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=2017-01-20T15:29:34+00:00
Cached update:	2017-01-20T15:29:38+00:00
Now set to:	update=2017-01-20T15:29:38+00:00
$ drush php-eval '(new Drupal\cacheproblem\CacheProblem(\Drupal::cache("foo")))->test();'
Previously:	update=2017-01-20T15:29:38+00:00
Cached update:	2017-01-20T15:29:54+00:00
Now set to:	update=2017-01-20T15:29:54+00:00

The cache has (incorrectly) warmed up between requests, because it is now storing the data in a cache_foo_bar SQL table, not in memory:

mysql> SELECT * FROM cache_foo_bar;
+--------+---------------------------+--------+----------------+------------+------+----------+
| cid    | data                      | expire | created        | serialized | tags | checksum |
+--------+---------------------------+--------+----------------+------------+------+----------+
| update | 2017-01-20T15:44:41+00:00 |     -1 | 1484927081.763 |          0 |      | 0        |
+--------+---------------------------+--------+----------------+------------+------+----------+
1 row in set (0.00 sec)

Proposed resolution

How this can be resolved isn't clear, but behaviour should be consistent and undefined behaviour warned about:

* Either the DI container needs to spot that the configuration is inconsistent (if that's even possible) and abort
* Or the cache & backend integration needs to be impervious to the DI service name.

Remaining tasks

1. Work out what the tasks are!

User interface changes

None.

API changes

None (this is undefined behaviour.)

Data model changes

None.

📌 Task
Status

Needs work

Version

10.1

Component
Cache 

Last updated 12 days ago

Created by

🇬🇧United Kingdom jp.stacey

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇬🇧United Kingdom catch

    Some validation seems sensible, but throwing an exception would potentially break existing sites as soon as they update. Maybe an assert() so it only breaks on local development?

    Also think this mostly a DX improvement and not a bug as such, so downgrading to a task.

Production build 0.71.5 2024