
# Caching

Queuety enthält eine Cache-Ebene, die Datenbankabfragen auf häufig genutzten Codepfaden reduziert, etwa bei Warteschlangen-Pausenprüfungen, Ratenbegrenzungszählern, Workflow-Statusabfragen und Sperrvorgängen. Der Cache wird automatisch initialisiert, wenn du `Queuety::init()` aufrufst.

## Cache-Schnittstelle

Alle Cache-Backends implementieren `Queuety\Contracts\Cache`:

| Methode | Rückgabe | Beschreibung |
|---|---|---|
| `get( string $key )` | `mixed` | Ruft einen Wert ab. Gibt `null` zurück, wenn er nicht gefunden wurde oder abgelaufen ist. |
| `set( string $key, mixed $value, int $ttl = 0 )` | `void` | Speichert einen Wert. Eine TTL von 0 bedeutet, dass er nicht abläuft. |
| `delete( string $key )` | `void` | Entfernt einen Wert. |
| `has( string $key )` | `bool` | Prüft, ob ein Schlüssel vorhanden und nicht abgelaufen ist. |
| `add( string $key, mixed $value, int $ttl = 0 )` | `bool` | Setzt einen Wert nur, wenn der Schlüssel noch nicht vorhanden ist (atomar). Gibt `true` zurück, wenn der Wert gesetzt wurde. |
| `flush()` | `void` | Entfernt alle Einträge aus dem Cache. `ApcuCache::flush()` ruft `apcu_clear_cache()` auf, wodurch alle APCu-Einträge auf dem Server gelöscht werden, nicht nur die von Queuety. |

## Integrierte Backends

### MemoryCache (Standard)

`Queuety\Cache\MemoryCache` ist ein prozessweiter Cache auf Array-Basis. Einträge werden in einem Array vom Typ PHP gespeichert und gehen beim Beenden des Prozesses verloren. Dies ist das Standard-Backend, wenn APCu nicht verfügbar ist.

Es benötigt keine Erweiterungen, eignet sich gut für Deployments mit einem Worker und hält die Prozesse der einzelnen Worker voneinander getrennt.

### ApcuCache

`Queuety\Cache\ApcuCache` nutzt die APCu-Erweiterung für gemeinsam genutzten Speicher zwischen allen PHP-Prozessen auf demselben Server. Allen Schlüsseln wird automatisch `queuety:` vorangestellt, um Kollisionen mit anderen Anwendungen zu vermeiden.

Dieses Backend benötigt die Erweiterung `php-apcu`, teilt Cache-Einträge zwischen Workern auf demselben Server und ermöglicht wirklich atomare Aufrufe von `add()` über `apcu_add()`.

## Automatische Erkennung

`Queuety\Cache\CacheFactory` wählt automatisch das beste verfügbare Backend aus:

Wenn `apcu_store()` existiert und `apcu_enabled()` `true` zurückgibt, verwendet Queuety `ApcuCache`. Andernfalls wird auf `MemoryCache` zurückgegriffen. Das geschieht innerhalb von `Queuety::init()`, daher ist für das Standardverhalten keine zusätzliche Konfiguration nötig.

## Was im Cache landet

Die Cache-Ebene wird intern von mehreren Subsystemen verwendet:

| Daten | Zweck |
|---|---|
| Pausenstatus der Warteschlange | Vermeidet eine Datenbankabfrage bei jeder Iteration der Worker-Schleife |
| Ratenbegrenzungszähler | Erfasst Ausführungen im Arbeitsspeicher statt in der Datenbank |
| Workflow-Status | Reduziert Lesezugriffe bei der Weiterentwicklung mehrstufiger Workflows |
| Sperrstatus | Beschleunigt Prüfungen auf vorhandene Sperren für eindeutige Jobs und Mutex-Middleware |

## TTL-Konfiguration

Die Standard-TTL des Caches beträgt 5 Sekunden. Sie gilt für den Pausenstatus der Warteschlange und Ratenbegrenzungszähler; Workflow-Status und Statusdaten werden für festgelegte 2 Sekunden zwischengespeichert, die sich durch die Konstante nicht ändern. Überschreibe den Standardwert mit der Konstante `QUEUETY_CACHE_TTL` in deiner `wp-config.php`:

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

Eine kürzere TTL bedeutet häufigere Datenbankabfragen, aber aktuellere Daten. Eine längere TTL verringert die Datenbanklast, führt jedoch zu veralteteren Daten. Für die meisten Deployments sind die standardmäßigen 5 Sekunden ein guter Mittelweg.

## Eigenes Cache-Backend

Um ein eigenes Cache-Backend (Redis, Memcached oder etwas anderes) zu verwenden, implementiere die Schnittstelle `Contracts\Cache` und rufe `Queuety::set_cache()` vor `Queuety::init()` auf:

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

Wenn `set_cache()` vor `init()` aufgerufen wird, wird die automatische Erkennung durch die Factory vollständig übersprungen und dein eigenes Backend verwendet.

## Auf den Cache zugreifen

Die aktive Cache-Instanz jederzeit abrufen:

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

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

Dadurch wird das aktuell aktive Backend zurückgegeben (MemoryCache, ApcuCache oder deine eigene Implementierung).
