CommunitySchreiben & Editierengithub.com

gplanchat/durable-skill

Claude Code-Skill: Schreiben von langlebigen Workflows, Aktivitäten und Nexus-Operationen in PHP

Was ist durable-skill?

Dieser Skill unterstützt Entwickler beim Erstellen zuverlässiger, langlebiger (durable) Workflows in PHP unter Verwendung des Frameworks von gplanchat/durable. Er basiert auf dem Temporal-Workflow-Modell und ermöglicht es, geschäftskritische Prozesse so zu schreiben, dass sie auch nach Neustarts oder Ausfällen sicher fortgesetzt werden können. Der Skill erklärt die drei grundlegenden Komponenten: Workflows (reine PHP-Klassen mit `#[AsWorkflow]`-Attribut), Aktivitäten (vertraglich definierte Schnittstellen mit `#[AsActivityMethod]`) und Nexus-Operationen (serviceübergreifende Aufrufe über `#[AsNexusOperation]`). Ein zentrales Prinzip ist die Determinismus-Regel: Workflow-Code muss bei Wiederholung immer dasselbe Ergebnis liefern, weshalb alle nicht-deterministischen Operationen (wie Datenbankabfragen, HTTP-Aufrufe oder Zufallswerte) in Aktivitäten ausgelagert werden. Unterstützt werden PHP-Frameworks wie Symfony, Sylius und Magento; der Skill enthält Verweise auf Referenzdokumente zu Migrationen, Signalen, Timern und Fehlerbehandlung sowie einen Rector-Regelsatz zur automatischen Code-Migration zwischen Framework-Versionen.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add gplanchat/durable-skill

Installed? Explore more Schreiben & Editieren skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Schreiben von langlebigem Code (Durable Code)

Ein Workflow ist eine einfache PHP-Klasse. Keine Basisklasse, kein Interface, kein Framework-Typ in ihrer Signatur. Was ihn langlebig macht, ist, dass die Engine ihn aus einem Journal wiederholt – daher ist die einzige wirklich bindende Regel die Determinismus.

Die drei Formen

#[AsWorkflow('checkout')]                       // der Name, den der Cluster kennt
final class CheckoutWorkflow
{
    public function __construct(
        private readonly WorkflowEnvironment $environment,
    ) {}

    #[AsWorkflowMethod]                          // genau eine pro Workflow-Klasse
    public function run(string $orderId): string
    {
        $orders = $this->environment->activityStub(OrderActivities::class);

        $receipt = $this->environment->await($orders->charge($orderId));
        $this->environment->sleep(Duration::seconds(30), 'Abkühlphase');

        return $this->environment->await($orders->notify($receipt));
    }
}
interface OrderActivities                        // der VERTRAG trägt die Namen
{
    #[AsActivityMethod(name: 'shop.order.charge')]
    public function charge(string $orderId): string;
}

final class DoctrineOrderActivities implements OrderActivities   // der HANDLER erledigt die Arbeit
{
    public function charge(string $orderId): string { /* echte Seiteneffekte hier */ }
}
#[AsNexusService('billing')]                     // ein anderes Team, eine andere Bereitstellung
interface BillingContract
{
    #[AsNexusOperation('check')]
    public function check(string $order, int $amountInCents, string $currency): array;
}

Schreiben Sie einen Aktivitätsnamen niemals als String an der Aufrufstelle. Der Stub liest die Attribute des Vertrags, daher lebt der Name an genau einer Stelle. Dies ist der mit Abstand häufigste Weg, einen bestehenden Workflow zu brechen: Benennen Sie die Methode um, behalten Sie das Attribut bei, und laufende Ausführungen finden ihre Aktivität trotzdem.

Die bindende Regel: Der Workflow-Körper wird wiederholt

Alles in einer #[AsWorkflowMethod]-Methode wird jedes Mal von vorne ausgeführt, wenn die Engine die Ausführung fortsetzt – möglicherweise in einem anderen Prozess, Tage später. Daher muss der Körper beim Wiederholen die gleichen Antworten liefern:

Niemals im Workflow-KörperVerwenden Sie stattdessen
rand(), uniqid(), time(), new \DateTime()$environment->sideEffect(fn() => …) – das Ergebnis wird einmal protokolliert
sleep(), usleep()$environment->sleep($duration, 'warum wir warten')
Eine Datenbankabfrage, ein HTTP-Aufruf, ein Dateischreibvorgangeine Aktivität
if (getenv(…)) zur Verzweigung bei Bereitstellung$environment->version($changeId, $min, $max)

Eine Aktivität ist der Ort, an den Nichtdeterminismus gehört. Sie wird einmal pro Versuch ausgeführt, ihr Ergebnis wird im Journal festgehalten, und bei Wiederholung antwortet das Journal anstelle des Codes.

⚠ Eine Aktivität wird wiederholt; schreiben Sie sie so, dass ein zweiter Versuch sicher ist. Die Engine garantiert, dass das Ergebnis einmal aufgezeichnet wird, nicht, dass Ihr Seiteneffekt nur einmal auftritt. Eine Karte zweimal zu belasten ist ein geschäftlicher Vorfall, kein Framework-Fehler.

Warten

Alles Planbare gibt ein Awaitable zurück. Nichts passiert, bis Sie darauf warten – das ist auch der Weg zur Parallelität:

$a = $stub->reserve($order);                     // geplant, nicht abgewartet
$b = $stub->quote($order);
[$reserved, $quoted] = $this->environment->await($this->environment->all($a, $b));

$first = $this->environment->await($this->environment->any($a, $b));
$twoOfThree = $this->environment->await($this->environment->some(2, $a, $b, $c));

await() akzeptiert eine optionale Frist: await($awaitable, Duration::minutes(5)).

Referenzdateien

Lesen Sie die benötigte Datei, nicht alle drei:

  • references/workflows.md – Signale, Updates, Child-Workflows, Timer, continueAsNew, Versionierung und wie eine Ausführung gestartet wird (niemals inline in einer Webanfrage).
  • references/activities.md – ActivityOptions, Wiederholungsstrategie, die vier Timeouts, nicht wiederholbare Ausnahmen, Heartbeats, Abbruch.
  • references/nexus.md – Nexus-Verträge, warum sich ein Vertrag in zwei aufspaltet, wenn ein Workflow eine Operation erfüllt, und die Nutzlastfalle, die stillschweigend fehlschlägt.
  • references/migrations.md – Lesen Sie dies, bevor Sie vorhandenen Code berühren. Wechsel vom Temporal PHP SDK oder von einer Durable-Version zur nächsten: gplanchat/durable-rector übernimmt das Umschreiben, und die Referenz handelt hauptsächlich von den fünf Dingen, die seine Regeln nicht erraten können – zwei davon schlagen stillschweigend auf einem bereits laufenden Server fehl.

Bevor Sie den Code zurückgeben

  • Eine #[AsWorkflowMethod]-Methode pro Workflow-Klasse, und die Klasse ist dem Host deklariert (Symfony/Sylius autoconfiguren sie; Magento listet sie in di.xml).
  • Jeder Aktivitätsaufruf erfolgt über einen aus einem Vertrag erstellten Stub – keine String-Namen.
  • Nichts Nichtdeterministisches im Workflow-Körper.
  • Jeder Timer hat eine Zusammenfassung: Sie benennt die Zeile im Beobachtungszeitstrahl, und TimerScheduled sagt einem Operator um 3 Uhr morgens gar nichts.
  • Der Workflow fängt nichts ab, was er nicht kompensieren kann. Ein nicht behandelter Fehler beendet die Ausführung und ist sichtbar; ein verschluckter hinterlässt eine halb verarbeitete Bestellung und schweigt.

Verwandte Skills