Arbeit mit Aufgabenwarteschlangen in PHP: Vom Einfachen zum Komplexen
In modernen Webanwendungen besteht häufig die Notwendigkeit, ressourcenintensive oder langwierige Operationen auszuführen, ohne den Benutzer warten zu lassen. Das Versenden von E-Mail-Benachrichtigungen, das Generieren von Berichten, die Bildverarbeitung, die Integration mit externen APIs – all diese Aufgaben eignen sich ideal für die asynchrone Ausführung. Genau hier kommen Aufgabenwarteschlangen (job queues) ins Spiel. In diesem Artikel werden wir detailliert betrachten, wie man die Arbeit mit Warteschlangen in PHP implementiert und optimiert, angefangen bei den einfachsten Lösungen bis hin zu industriellen Werkzeugen.
Was ist eine Aufgabenwarteschlange und warum wird sie benötigt?
Eine Aufgabenwarteschlange (job queue) ist ein Mechanismus, der es ermöglicht, die Ausführung einer bestimmten Arbeit auf später zu verschieben. Anstatt die Aufgabe sofort im Rahmen einer HTTP-Anfrage auszuführen, legen Sie sie in eine Warteschlange. Ein spezieller Worker oder eine Gruppe von Workern entnehmen die Aufgaben aus der Warteschlange und verarbeiten sie im Hintergrund.
Die wichtigsten Vorteile der Verwendung von Warteschlangen:
- Schnellere Antwort an den Benutzer: Der Benutzer erhält sofort eine Antwort, während die schwere Arbeit asynchron erledigt wird.
- Skalierbarkeit: Sie können mehrere Worker für die parallele Verarbeitung von Aufgaben starten.
- Zuverlässigkeit: Wenn eine Aufgabe fehlschlägt (z. B. aufgrund eines temporären Fehlers), kann sie später wiederholt werden.
- Entlastung des Hauptservers: Hintergrundprozesse blockieren nicht die Verarbeitung neuer HTTP-Anfragen.
Einfache Warteschlange auf Basis einer Datenbank
Der einfachste Weg, eine Warteschlange in PHP zu organisieren, ist die Verwendung einer Tabelle in einer Datenbank (z. B. MySQL). Dieser Ansatz erfordert keine Installation zusätzlicher Software und eignet sich hervorragend für kleine Projekte.
Schritt 1: Erstellen der Tabelle jobs
CREATE TABLE jobs ( id INT AUTO_INCREMENT PRIMARY KEY, queue_name VARCHAR(255) DEFAULT 'default', payload TEXT NOT NULL, status ENUM('pending', 'processing', 'completed', 'failed') DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, available_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, attempts INT DEFAULT 0);Schritt 2: Hinzufügen einer Aufgabe zur Warteschlange
function addJob(string $queueName, array $data): void { $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password'); $stmt = $pdo->prepare( "INSERT INTO jobs (queue_name, payload, available_at) VALUES (?, ?, NOW())" ); $stmt->execute([$queueName, json_encode($data)]);}
// Beispiel VerwendungaddJob('emails', ['to' => 'user@example.com', 'subject' => 'Hallo!']);Schritt 3: Erstellen eines Workers (worker.php)
// Endlosschleife zur Verarbeitung von Aufgabenwhile (true) { $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password'); // Aufgabe mit Zeilensperre erfassen $stmt = $pdo->prepare( "SELECT * FROM jobs WHERE status = 'pending' AND available_at <= NOW() ORDER BY id ASC LIMIT 1 FOR UPDATE" ); $stmt->execute(); $job = $stmt->fetch(PDO::FETCH_ASSOC); if ($job) { // Als "in Bearbeitung" markieren $updateStmt = $pdo->prepare("UPDATE jobs SET status = 'processing' WHERE id = ?"); $updateStmt->execute([$job['id']]); try { // Ausführung der Aufgabe $data = json_decode($job['payload'], true); processJob($data); // Als erledigt markieren $pdo->prepare("UPDATE jobs SET status = 'completed' WHERE id = ?") ->execute([$job['id']]); } catch (Exception $e) { // Fehlerbehandlung $attempts = $job['attempts'] + 1; if ($attempts < 3) {