
# 캐싱

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` 확장이 필요합니다. 같은 서버의 워커 간 캐시 항목을 공유하고 `apcu_add()`를 통해 `add()`을 진정한 원자 연산으로 처리합니다.

## 자동 감지

`Queuety\Cache\CacheFactory`는 사용 가능한 최적의 백엔드를 자동으로 선택합니다:

`apcu_store()`가 있고 `apcu_enabled()`가 `true`를 반환하면 Queuety는 `ApcuCache`를 사용합니다. 그렇지 않으면 `MemoryCache`로 대체됩니다. 이 과정은 `Queuety::init()` 안에서 이루어지므로 기본 동작에 추가 설정이 필요하지 않습니다.

## 캐시되는 항목

캐시 계층은 여러 하위 시스템에서 내부적으로 사용됩니다:

| 데이터 | 용도 |
|---|---|
| 대기열 일시 중지 상태 | 워커 루프를 반복할 때마다 발생하는 데이터베이스 쿼리를 방지합니다 |
| 속도 제한 카운터 | 실행 횟수를 데이터베이스 대신 메모리에서 추적합니다 |
| 워크플로 상태 | 여러 단계의 워크플로 진행 중 읽기 횟수를 줄입니다 |
| 잠금 상태 | 고유 작업과 뮤텍스 미들웨어의 잠금 존재 여부를 빠르게 확인합니다 |

## TTL 설정

기본 캐시 TTL은 5초입니다. 대기열 일시 중지 상태와 속도 제한 카운터에 적용되며, 워크플로 상태와 상태 읽기는 상수로 변경할 수 없는 고정된 2초 동안 캐시됩니다. 기본값을 재정의하려면 `wp-config.php`의 `QUEUETY_CACHE_TTL` 상수를 사용하세요:

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

TTL이 짧으면 데이터베이스 쿼리가 더 자주 발생하지만 최신 데이터를 얻을 수 있습니다. TTL이 길면 데이터베이스 부하가 줄어들지만 데이터가 오래된 상태로 남을 수 있습니다. 대부분의 배포 환경에서는 기본값인 5초가 적절한 균형입니다.

## 사용자 지정 캐시 백엔드

사용자 지정 캐시 백엔드(Redis, Memcached 또는 기타)를 사용하려면 `Contracts\Cache` 인터페이스를 구현하고 `Queuety::init()`보다 먼저 `Queuety::set_cache()`를 호출하세요:

```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 );
```

`init()`보다 먼저 `set_cache()`를 호출하면 팩토리의 자동 감지가 완전히 건너뛰어지고 사용자 지정 백엔드가 사용됩니다.

## 캐시 액세스

언제든 활성 캐시 인스턴스를 가져올 수 있습니다:

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

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

현재 활성화된 백엔드(MemoryCache, ApcuCache 또는 사용자 지정 구현)가 반환됩니다.
