Invalidation

As mentioned in the introduction and events documentation, Relay will invalidate its in-memory cache in real-time. There is an average delay of 100μs / 0.1ms for Redis to inform Relay about invalidations, plus whatever the network latency is.

Even tho it is is strongly discouraged, some rare users may want to disable Relay’s invalidations using the OPT_CLIENT_INVALIDATIONS option.

Multitenancy limitations

Redis’ invalidation system is not designed for use with multiple databases and will cause unnecessary flushing of Relay’s memory when more than one database is used.

To bypass most of these limitations, it is vital to set a unique prefix for each database connection. We suggest using the format db0:, db1: and so on.

$relay->setOption(Relay::OPT_PREFIX, 'db4:');

Unfortunately, due to Redis’ design, Relay isn’t aware of the database index when FLUSHDB is called and will flush it’s entire memory. If you’re curious, read about the technical details.

Invalidation listeners

In some cases you may wish to listen for the aforementioned invalidation events, however because of PHP’s synchronous nature, when using event listeners the application must request Relay to dispatch registered event listeners.

This is done by calling dispatchEvents() before cache any operation, as well as automated using native PHP ticks or asynchronous libraries.

Calling dispatchEvents()

Dispatching invalidations is extremely fast and memory efficient, but calling dispatchEvents() before each cache operation can be a hassle.

$relay->dispatchEvents();
$relay->get('users:count');

Therefore it’s recommended to encapsulate your cache implementation.

use Relay\{Relay, Event};

class Cache extends Psr\Cache\CacheItemPoolInterface
{
    public function __construct()
    {
        $this->relay = new Relay(host: '127.0.0.1', port: 6379);

        $this->relay->listen(fn (Event $event) => match ($event->type) {
            $event::Flushed => $this->clear(),
            $event::Invalidated => $this->deleteItem($event->key),
        });
    }

    public function getItem($key)
    {
        $this->relay->dispatchEvents();

        return $this->relay->get($key);
    }

    public function hasItem($key) {
        $this->relay->dispatchEvents();

        return $this->relay->exists($key);
    }

    /**
     * @see https://github.com/cachewerk/relay/tree/main/src/Psr/SimpleCache
     */
}

Using ticks

Ticks are an underused and powerful feature of PHP.

Using ticks to dispatch invalidation is convenient, however the tick count is a delicate balance between performance and reliability.

When ticks are declared for a file, Relay will automatically call registered event listeners every N ticks.

<?php

declare(ticks = 10);

$relay = new Relay(host: '127.0.0.1', port: 6379);

$relay->listen(function (Relay\Event $event) {
    echo "Callback for {$event->type}:{$obj_event->key}\n";
});

while (true) {
    $key = 'ticks:' . mt_rand(1, 10);
    $relay->set($key, $key);

    echo "Set `{$key}`\n";

    $relay->get($key);
    usleep(100000);
}

Event loops

Use the event loop of any asynchronous library such as ReactPHP, Swoole or Amp to call dispatchEvents().