Praktický návod

Jak automatizovat zpracování objednávek

Řiď objednávku explicitním workflow a pomalé vedlejší efekty předávej spolehlivým workerům.

25 minut · Workflow a fronty

Nejdřív stručně

Stav je fakt, automatizace je reakce

Objednávka má malý počet povolených stavů a přechodů. E-mail, export do ERP nebo vytvoření zásilky jsou reakce na událost, ne další nejasné hodnoty ve sloupci status.

Datovou změnu a zápis události spoj v jedné databázové transakci. Zprávy pak může bezpečně zpracovat fronta i po dočasném výpadku externí služby.

Připrav si

Popiš proces dřív než kód

Automatizace bez vlastníka a hranic končí skriptem, který mění objednávku z několika míst zároveň.

  • Diagram stavů, povolených přechodů a podmínek, kdo je smí vyvolat.
  • Seznam vedlejších efektů: platba, sklad, doprava, doklad, ERP a komunikace se zákazníkem.
  • Jednoznačná ID objednávek, událostí a pokusů o zpracování.
  • Frontu s acknowledgement, retry, dead-letter queue a monitoringem workerů.

Kroky 1 až 3

Odděl rozhodnutí od provedení

Synchronně rozhodni a ulož nový stav. Vše, co může trvat nebo selhat, dokonči asynchronně.

1. Vytvoř stavový automat

  1. Použij stavy například new, awaiting_payment, paid, picking, shipped a cancelled; jejich význam napiš jako obchodní pravidlo.
  2. Každý přechod má guard podmínky. Paid vyžaduje potvrzenou platbu, shipped existující zásilku a cancelled respektuje již expedované položky.
  3. Přechod provádí jediný aplikační use-case. Controller, cron ani worker nesmí stav přepsat napřímo.
  4. Historii změn ukládej zvlášť se starým a novým stavem, důvodem, aktérem a časem.
php bin/console workflow:dump order
Oficiální Symfony Workflow dokumentace

2. Ulož změnu a událost atomicky

  1. Po úspěšném přechodu vytvoř událost pojmenovanou jako minulý fakt, například OrderPaid nebo OrderCancelled.
  2. Payload obsahuje event ID, order ID, verzi schématu, occurred_at a jen data potřebná příjemci. Nevkládej do něj serializovanou ORM entitu.
  3. Objednávku i událost zapiš v jedné transakci do outbox tabulky. Publisher potvrzené řádky následně odešle do fronty.
  4. Optimistický lock nebo unikátní business klíč zabrání dvěma souběžným požadavkům provést stejný přechod dvakrát.
BEGIN; UPDATE orders ...; INSERT INTO outbox ...; COMMIT;
Oficiální PostgreSQL dokumentace k transakcím

3. Provozuj idempotentní workery

  1. Worker nejprve ověří event ID nebo business klíč. Opakované doručení vrátí úspěch bez druhého e-mailu, zásilky či faktury.
  2. Acknowledgement odešli až po potvrzeném lokálním zápisu. Dočasné chyby opakuj s exponenciálním odstupem a jitterem.
  3. Trvalé chyby po omezeném počtu pokusů přesuň do dead-letter queue s kontextem, ale bez tajných údajů.
  4. Výjimky zpřístupni operátorovi: může opravit vstup, bezpečně zopakovat krok a vidí úplnou auditní stopu.
php bin/console messenger:consume async --time-limit=3600
Oficiální Symfony Messenger dokumentace

Krok 4

Simuluj duplicity i výpadky

Proces je spolehlivý teprve tehdy, když stejný výsledek vznikne po opakování, restartu i souběhu.

  1. Pošli událost dvakrát

    Worker provede vedlejší efekt jednou a druhé doručení označí jako již zpracované.

    php bin/phpunit --filter OrderWorkflowIdempotency
  2. Ukonči worker po externím volání

    Po restartu nezdvojí zásilku ani doklad; používá idempotency key externího systému nebo lokální mapování výsledku.

  3. Vyvolej dvě změny současně

    Jedna uspěje a druhá dostane čitelný konflikt. Historie i outbox odpovídají pouze potvrzenému přechodu.

Když to zlobí

Nejčastější chyby

Objednávka je paid, ale událost se neposlala

Datový zápis a publish nejsou atomické. Použij transactional outbox a samostatný opakovatelný publisher.

Zákazník dostal stejný e-mail dvakrát

Consumer předpokládá doručení právě jednou. Přidej idempotency key a perzistentní záznam dokončeného efektu.

Zpráva se opakuje bez konce

Rozliš dočasnou a trvalou chybu, omez retry a po vyčerpání pokusů ji přesuň do DLQ s alertem.

Stav mění controller i worker

Přesuň přechod do jednoho aplikačního use-casu a všechny vstupy veď přes něj.

Hotovo

Objednávka má řiditelné workflow.

Přechody jsou explicitní, události se neztratí a workery bezpečně zvládají opakované doručení i výpadky služeb.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.