
# Кэширование

Queuety включает уровень кэширования, сокращающий число запросов к базе данных в часто используемых сценариях, таких как проверка приостановки очереди, счетчики ограничений частоты запросов, поиск состояния рабочего процесса и операции с блокировками. Кэш инициализируется автоматически при вызове `Queuety::init()`.

## Интерфейс кэша

Все серверные реализации кэша реализуют `Queuety\Contracts\Cache`:

| Метод | Возвращает | Описание |
|---|---|---|
| `get( string $key )` | `mixed` | Получает значение. Возвращает `null`, если значение не найдено или срок его действия истёк. |
| `set( string $key, mixed $value, int $ttl = 0 )` | `void` | Сохраняет значение. TTL 0 означает отсутствие срока действия. |
| `delete( string $key )` | `void` | Удаляет значение. |
| `has( string $key )` | `bool` | Проверяет, существует ли ключ и не истёк ли срок его действия. |
| `add( string $key, mixed $value, int $ttl = 0 )` | `bool` | Устанавливает значение, только если ключ ещё не существует (атомарно). Возвращает `true`, если значение было установлено. |
| `flush()` | `void` | Удаляет все элементы из кэша. `ApcuCache::flush()` вызывает `apcu_clear_cache()`, который очищает все записи APCu на сервере, а не только записи Queuety. |

## Встроенные серверные части

### MemoryCache (по умолчанию)

`Queuety\Cache\MemoryCache` — кэш на основе массива, отдельный для каждого процесса. Элементы хранятся в массиве PHP и теряются при завершении процесса. Это серверная часть по умолчанию, если APCu недоступен.

Для неё не нужны расширения; она хорошо подходит для развёртываний с одним рабочим процессом и изолирует каждый процесс от остальных.

### ApcuCache

`Queuety\Cache\ApcuCache` использует расширение APCu для общей памяти между всеми процессами PHP на одном сервере. Ко всем ключам автоматически добавляется префикс `queuety:`, чтобы избежать конфликтов с другими приложениями.

Для этой серверной части требуется расширение `php-apcu`; записи кэша общие для рабочих процессов на одном сервере, а `add()` выполняется действительно атомарно с помощью `apcu_add()`.

## Автоматическое определение

`Queuety\Cache\CacheFactory` автоматически выбирает наиболее подходящую доступную серверную часть:

Если `apcu_store()` существует, а `apcu_enabled()` возвращает `true`, Queuety использует `ApcuCache`. В противном случае используется `MemoryCache`. Это происходит внутри `Queuety::init()`, поэтому для поведения по умолчанию дополнительная настройка не требуется.

## Какие данные кэшируются

Уровень кэширования используется несколькими подсистемами:

| Данные | Назначение |
|---|---|
| Состояние приостановки очереди | Позволяет не выполнять запрос к базе данных при каждой итерации цикла рабочего процесса |
| Счётчики ограничений частоты | Отслеживают число выполнений в памяти, а не в базе данных |
| Состояние рабочего процесса | Сокращает число чтений при переходах между этапами рабочего процесса |
| Состояние блокировки | Ускоряет проверку наличия блокировки для уникальных заданий и промежуточного ПО mutex |

## Настройка TTL

По умолчанию TTL кэша составляет 5 секунд. Он применяется к состоянию приостановки очереди и счётчикам ограничений частоты; чтение статуса и состояния рабочего процесса кэшируется на фиксированные 2 секунды, которые эта константа не меняет. Переопределите значение по умолчанию с помощью константы `QUEUETY_CACHE_TTL` в вашем `wp-config.php`:

```php
define( 'QUEUETY_CACHE_TTL', 10 ); // 10 seconds
```

Меньший TTL означает более частые запросы к базе данных, но более актуальные данные. Больший TTL снижает нагрузку на базу данных, но увеличивает вероятность устаревших данных. Для большинства развёртываний значение по умолчанию — 5 секунд — обеспечивает хороший баланс.

## Пользовательская серверная часть кэша

Чтобы использовать пользовательскую серверную часть кэша (Redis, Memcached или любую другую), реализуйте интерфейс `Contracts\Cache` и вызовите `Queuety::set_cache()` до `Queuety::init()`:

```php
use Queuety\Contracts\Cache;
use Queuety\Queuety;

class RedisCache implements Cache {
    public function get( string $key ): mixed { /* ... */ }
    public function set( string $key, mixed $value, int $ttl = 0 ): void { /* ... */ }
    public function delete( string $key ): void { /* ... */ }
    public function has( string $key ): bool { /* ... */ }
    public function add( string $key, mixed $value, int $ttl = 0 ): bool { /* ... */ }
    public function flush(): void { /* ... */ }
}

// Set the cache before init() so all subsystems use it.
Queuety::set_cache( new RedisCache() );
Queuety::init( $connection );
```

Если `set_cache()` вызван до `init()`, автоматическое определение фабрики полностью пропускается и используется ваша пользовательская серверная часть.

## Доступ к кэшу

Получить активный экземпляр кэша можно в любое время:

```php
$cache = Queuety::cache();

$cache->set( 'my_key', 'my_value', 60 );
$value = $cache->get( 'my_key' );
```

Возвращается серверная часть, активная в данный момент (MemoryCache, ApcuCache или ваша пользовательская реализация).
