Fronta a worker: webhook odpovi hned, praci udelaji workeri
Webhook uz nic nevykonava v requestu. Zapise udalost do fronty a odpovi 202 do jednotek milisekund; strom vykona worker na pozadi. Za konektory nerucime, takze cekat na cizi sluzbu v requestu znamena ztracet udalosti pri timeoutu. Fronta ma opakovani s rostouci prodlevou (30 s, 2 min, 10 min, hodina), spravedlive poradi po firmach (jedna firma s tisicem udalosti nezablokuje ostatni), navrat zaseknutych behu po restartu a uklid hotovych. Marna chyba se neopakuje - chybejici skript za minutu existovat nezacne. Tri druhy spoustecu: push (webhook), vnitrni udalost (vznik a zmena ticketu) a pull, tedy pravidelne dotazovani u sluzeb bez webhooku (posta, zpravy). Planovac jen rekne "je cas", samotny dotaz je prvni krok stromu, takze ma zaznam v logu a opakuje se pri chybe jako cokoliv jineho. Kontrakt tela webhooku: kazdy parametr ma cestu (data.order.id, errors.0.message), takze jde napojit i odesilatel s vnorenym modelem. U adresy je metoda, ukazka tela a kopiruje se cela adresa vcetne domeny. Vnitrni kroky, ktere sahaji do naseho uloziste: ticket/upsert (zaloz nebo dopln podle externiho ID), assign-least-busy, assign-by-external, set-type, set-stage, add-tags, set-status, incident/create, flow/pause a flow/log. Faze ticketu jako treti osa vedle stavu a stitku. Stav je zivotni cyklus a pocitaji se z nej statistiky, faze je workflow daneho typu a muze byt jen jedna, takze se na ni da spolehnout v podmince. ID z cizich aplikaci u resitele: voicebot posle voicebotId a ticket skonci u toho, komu patri. Vazba je na jednom miste, ne v kazde automatizaci. Kazda chyba zaklada incident se dvema urovnemi: impact cte klient a je srozumitelny, detail cte admin a je v nem cely beh, ktery krok selhal, cele hlaseni a data na vstupu. Detail vidi jen spravce platformy. Ochrana proti smycce: automatizace navazana na zmenu ticketu ticket meni, cimz se spousti znovu - pri vyvoji to server polozilo. Resi to oznaceni behu pres AsyncLocalStorage a strop peti behu na jeden ticket za minutu. Upozorneni pri prideleni prace vcetne cisla u zalozky Tickety. Zivy dashboard: dlazdice nad nasimi daty na udalost, data z konektoru podle ttlSec s moznosti vynutit nacteni znovu. Opraveno: path a intervalSec u spoustece se pri ulozeni zahazovaly; nad seznamem neslo pouzit contains, takze na stitky neslo postavit podminku; novejsi vystup kroku ted prekryje starsi misto hlaseni konfliktu. Overeno dvema scenari proti bezicimu serveru, 34 kontrol: firma se skladem, expedici a IT, a hovory z voicebota (callSid do externiho ID, status do faze, prirazeni podle voicebotId, tri zpravy = jeden ticket se tremi udalostmi). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5d186dcd2e
commit
a57eca123e
@@ -47,7 +47,11 @@ React aplikaci ze slozky `dist/public`.
|
||||
| Telo akce jako strom | hotovo | tentyz editor jako automatizace |
|
||||
| Audit a prepnuti na jiny ucet | hotovo | prepnuti je vychozi jen pro cteni, vse v auditu |
|
||||
| Bugs a wishes | chybi | vyvojarska agenda, samostatna evidence vedle ticketu |
|
||||
| Beh automatizaci | castecne | strom se vykona, ale synchronne a bez fronty |
|
||||
| Beh automatizaci | hotovo | fronta, worker, opakovani, ochrana proti smycce |
|
||||
| Prijem udalosti do fronty | hotovo | webhook odpovi 202, praci dela worker |
|
||||
| Pravidelne dotazovani sluzeb | hotovo | planovac pro postu a zpravy, perioda u spoustece |
|
||||
| Upozorneni na pridelenou praci | hotovo | cislo u zalozky a hlaska v portalu |
|
||||
| Incident z chyby | hotovo | popis pro klienta, podrobnosti pro admina |
|
||||
| Uloziste konektoru | hotovo | Postgres, nebo JSON soubor. Udaje vzdy sifrovane |
|
||||
| Uloziste pro zbytek | hotovo | tickety, automatizace, incidenty, rozlozeni, entity |
|
||||
| Monetizace a cena za krok | navrh | popis v 16-monetizace.md, neni naprogramovane |
|
||||
@@ -127,4 +131,5 @@ pro frontu, beh kroku a rozpocet na 150 klientu, a
|
||||
| [17-nastaveni-a-prava.md](17-nastaveni-a-prava.md) | prava, typy, akce, widgety, prepnuti uctu |
|
||||
| [18-ticketovaci-system.md](18-ticketovaci-system.md) | udalosti, externi ID, statistiky, pohledy |
|
||||
| [19-kapacita-200-firem.md](19-kapacita-200-firem.md) | zmereno, co zvladne soucasny stav |
|
||||
| [20-fronta-a-runtime.md](20-fronta-a-runtime.md) | fronta, worker, spoustece, ochrana proti smycce |
|
||||
| [99-zmeny.md](99-zmeny.md) | zaznam zmen, nejnovejsi nahore |
|
||||
|
||||
@@ -36,6 +36,9 @@ Vyzaduji `Authorization: Bearer <token>`:
|
||||
| GET | `/api/dashboard/intake` |
|
||||
| POST | `/api/dashboard/intake/regenerate` |
|
||||
| GET | `/api/dashboard/settings/actions/:id/scope` |
|
||||
| GET | `/api/dashboard/notifications` |
|
||||
| POST | `/api/dashboard/notifications/read` |
|
||||
| GET | `/api/dashboard/runs` |
|
||||
| GET | `/api/dashboard/tickets` |
|
||||
| GET | `/api/dashboard/tickets/workload` |
|
||||
| GET | `/api/dashboard/tickets/:id` |
|
||||
@@ -227,6 +230,21 @@ tentyz klic.
|
||||
Neznamy `typeId` se zahodi a zaloguje, ticket vznikne bez typu. Odmitnout celou
|
||||
udalost kvuli jednomu poli by znamenalo ztratu dat.
|
||||
|
||||
## Fronta behu
|
||||
|
||||
Popis je v [20-fronta-a-runtime.md](20-fronta-a-runtime.md).
|
||||
|
||||
`POST /webhook/:token` vraci **202**, ne 200: data jsme prevzali a strom se
|
||||
vykona na pozadi. Vysledek se hleda v `GET /api/dashboard/runs` nebo v logu
|
||||
ticketu. Cekat na cizi sluzbu v requestu nejde - za jeji rychlost nerucime
|
||||
a odesilateli by vyprsel timeout.
|
||||
|
||||
`GET /webhook/:token` vraci **kontrakt**: co se v tele ceka, na jakych cestach
|
||||
a ukazku. Bez toho by musel ten, kdo webhook zapojuje, hadat.
|
||||
|
||||
`GET /api/dashboard/runs` ma u kazdeho behu cele chybove hlaseni, pocet pokusu
|
||||
a kdy se to zkusi znovu.
|
||||
|
||||
## Prava a navigace
|
||||
|
||||
`GET /api/dashboard/access` vraci `permissions` (efektivni prava po slouceni
|
||||
|
||||
@@ -37,6 +37,13 @@ Volající nikdy nezjišťuje, jestli běží Postgres, soubor, nebo pamět.
|
||||
| `hasPermission(...)` | `src/data/permissions.ts` | Jedna kontrola. Používá ji `crudRouter` i ruční handlery. |
|
||||
| `navFor(...)` | `src/data/tenantFeatures.ts` | Průnik toho, co firma má, a toho, na co má člověk právo. Navigace chodí ze serveru. |
|
||||
| `recordAudit(input)` | `src/data/audit.ts` | Zápis do auditu. Nevrací chybu a nečeká se - rozbitý audit nesmí rozbít aplikaci. |
|
||||
| `enqueue(input)` | `src/runtime/queue.ts` | Zařadí běh. Klíč proti dvojímu zařazení drží jeden běh na jednu událost. |
|
||||
| `claimBatch(limit)` | `src/runtime/queue.ts` | Vezme další práci, spravedlivě po firmách. Místo, kde nad Postgresem musí být SKIP LOCKED. |
|
||||
| `onTicketEvent(kind, ticket)` | `src/runtime/triggers.ts` | Změna ticketu zařadí navázané automatizace, včetně ochrany proti smyčce. |
|
||||
| `withRun(marker, work)` | `src/runtime/context.ts` | Označí, který běh práci způsobil. Bez toho automatizace spouští sama sebe. |
|
||||
| `findBuiltinStep(...)` | `src/runtime/builtinSteps.ts` | Kroky, které sahají do našeho úložiště, ne ven přes HTTP. |
|
||||
| `findPersonByExternalId(...)` | `src/data/people.ts` | Řešitel podle ID z cizí aplikace, například voicebotId. |
|
||||
| `notify(input)` | `src/data/notifications.ts` | Upozorní člověka. Nečeká se a nevyhazuje chyby, stejně jako audit. |
|
||||
| `runFlow(steps, context, options)` | `src/runtime/executor.ts` | Vykoná strom kroků. Nikdy nevyhodí výjimku, chyba je výsledek. Používá to akce na ticketu i webhook, aby se strom choval všude stejně. |
|
||||
| `widgetCatalog(tenantIds, userId)` | `src/data/widgets.ts` | Jediná definice toho, co jde položit na dashboard. Používá ji nabídka i kontrola ukládaného rozložení. |
|
||||
| `intakeEvent(input)` | `src/data/ticketStore.ts` | Přijme událost zvenku: podle externího ID buď založí ticket, nebo ji navěsí na existující. Jediná cesta, kterou se událost stává ticketem. |
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
# Fronta, worker a spouštěče
|
||||
|
||||
Jak se událost dostane od webhooku k vykonanému stromu. Rozbor kapacity je
|
||||
v [19-kapacita-200-firem.md](19-kapacita-200-firem.md), model ticketu
|
||||
v [18-ticketovaci-system.md](18-ticketovaci-system.md).
|
||||
|
||||
## Webhook odpoví hned, práci udělá worker
|
||||
|
||||
```
|
||||
POST /webhook/<token>
|
||||
-> kontrola těla podle kontraktu
|
||||
-> zápis do fronty
|
||||
-> 202 Accepted (do jednotek milisekund)
|
||||
|
||||
worker (na pozadí)
|
||||
-> vezme z fronty
|
||||
-> vykoná strom
|
||||
-> zapíše výsledek do logu ticketu
|
||||
-> při chybě naplánuje další pokus, nebo založí incident
|
||||
```
|
||||
|
||||
Odesílatel **nikdy nečeká** na cizí službu. Důvody:
|
||||
|
||||
- Za konektory neručíme. iDoklad může odpovídat pět sekund nebo být hodinu
|
||||
mimo. Kdyby se čekalo v requestu, odesílateli vyprší timeout a událost je
|
||||
pryč, přestože jsme ji dostali.
|
||||
- Pád procesu nesmí ztratit práci. Záznam ve frontě restart přežije,
|
||||
rozdělaný běh v paměti ne.
|
||||
- Bez fronty není kam si poznamenat, že se to má za minutu zkusit znovu.
|
||||
|
||||
Odpověď 202 znamená "převzali jsme to", ne "hotovo". Výsledek se hledá
|
||||
v `GET /api/dashboard/runs` nebo v logu ticketu.
|
||||
|
||||
## Co frontu plní
|
||||
|
||||
| Druh | Kdo to spustí | Příklad |
|
||||
| --- | --- | --- |
|
||||
| Push | cizí služba zavolá nás | e-shop pošle novou objednávku |
|
||||
| Vnitřní událost | něco se stalo u nás | vznikl nebo se změnil ticket |
|
||||
| Pull | ptáme se sami | e-mail, zprávy z Messengeru |
|
||||
|
||||
### Pull, tedy pravidelné dotazování
|
||||
|
||||
Většina služeb webhooky nemá. U e-mailu a schránek zpráv se **musíme ptát**.
|
||||
Dělá to plánovač: každých 30 sekund projde automatizace, jejichž spouštěč je
|
||||
"musí se obvolávat", a u těch, kterým uplynula perioda, zařadí běh.
|
||||
|
||||
Plánovač **sám nic nevolá**. Jen řekne "je čas" a samotný dotaz je první krok
|
||||
stromu. Díky tomu se dotazování chová stejně jako cokoliv jiného: má záznam
|
||||
v logu, opakuje se při chybě a jde ho změnit bez zásahu do kódu.
|
||||
|
||||
Výchozí periody: pošta 60 s, zprávy 30 s, plánovač 60 s. Automatizace si to
|
||||
může přepsat polem `intervalSec` u spouštěče, minimum je 10 sekund - kratší už
|
||||
není dotazování, ale útok na cizí službu.
|
||||
|
||||
Jeden čekající dotaz na automatizaci: když předchozí ještě běží, další se
|
||||
nezařadí. Jinak by se fronta zaplnila dotazy na službu, která stejně nestíhá.
|
||||
|
||||
## Kontrakt webhooku
|
||||
|
||||
Odesílatelé posílají různé tvary. Jeden `{"a":"aaa"}`, druhý celý model
|
||||
s vnořenými objekty a poli. Proto má každý parametr spouštěče **cestu**:
|
||||
|
||||
```json
|
||||
{
|
||||
"document": { "id": "D-99" },
|
||||
"errors": [{ "code": "OCR_FAIL", "message": "Nepodařilo se přečíst částku" }]
|
||||
}
|
||||
```
|
||||
|
||||
| Parametr | Cesta | Typ |
|
||||
| --- | --- | --- |
|
||||
| `docId` | `document.id` | string |
|
||||
| `errorMessage` | `errors.0.message` | string |
|
||||
|
||||
Ve stromu se pak píše `{{docId}}` bez ohledu na to, jak hluboko to odesílatel
|
||||
schoval. Celé tělo je navíc pod `_body`, takže se nic neztratí.
|
||||
|
||||
Chybějící povinný parametr vrací 400 s tím, který to je a kde se hledal.
|
||||
Přebytek v těle nevadí - odesílatel často posílá víc, než potřebujeme, a
|
||||
odmítnout ho kvůli tomu by znamenalo, že webhook nejde zapojit.
|
||||
|
||||
`GET` na tutéž adresu vrátí nápovědu: co se čeká, na jakých cestách a ukázku
|
||||
těla. V portálu je u adresy vidět totéž včetně metody, a kopíruje se **celá
|
||||
adresa včetně domény**.
|
||||
|
||||
## Opakování a vzdání se
|
||||
|
||||
| Pokus | Kdy |
|
||||
| --- | --- |
|
||||
| 1. | hned |
|
||||
| 2. | za 30 s |
|
||||
| 3. | za 2 min |
|
||||
| 4. | za 10 min |
|
||||
| 5. | za hodinu |
|
||||
|
||||
Pak běh skončí jako `failed` a zůstane k nahlédnutí. Nemaže se: bez záznamu
|
||||
by nikdo nezjistil, že se něco nestalo.
|
||||
|
||||
**Marná chyba se neopakuje vůbec.** Chybějící skript nebo neexistující skupina
|
||||
za minutu existovat nezačne, takže se běh rovnou vzdá. Opakuje se jen to, co
|
||||
může pominout: nedostupná služba, timeout.
|
||||
|
||||
## Incident z chyby
|
||||
|
||||
Každá chyba, kterou už nemá smysl zkoušet, založí incident se **dvěma
|
||||
úrovněmi**:
|
||||
|
||||
- `title` a `impact` čte **klient**. Bez názvů kroků a ID běhů: "Automatizace
|
||||
u ticketu TK-4822 nedoběhla do konce, data jsme neztratili."
|
||||
- `detail` čte **admin**. Je v něm všechno: která automatizace, který běh,
|
||||
kolik pokusů, který krok selhal, celé hlášení, výpis všech kroků a data,
|
||||
která přišla na vstupu.
|
||||
|
||||
`detail` se vrací **jen správci platformy**. Je to naše diagnostika, ne
|
||||
informace pro zákazníka.
|
||||
|
||||
Stejná příčina nezakládá druhý incident, dokud je první otevřený. Jinak by
|
||||
deset stejných chyb znamenalo deset incidentů a nikdo by se v tom nevyznal.
|
||||
|
||||
## Ochrana proti smyčce
|
||||
|
||||
Automatizace navázaná na změnu ticketu ticket změní, čímž se spustí znovu.
|
||||
Bez ochrany to server položí, což se při vývoji stalo.
|
||||
|
||||
Dvě pojistky:
|
||||
|
||||
1. **Označení běhu.** Změna, kterou udělala automatizace X, nespustí
|
||||
automatizaci X. Používá se na to `AsyncLocalStorage`, protože běží čtyři
|
||||
běhy naráz a obyčejná proměnná by patřila všem.
|
||||
2. **Strop na ticket.** Jedna automatizace smí nad jedním ticketem běžet
|
||||
nejvýš pětkrát za minutu. Chytí to i smyčku mezi dvěma automatizacemi,
|
||||
kterou první pojistka nepozná. Překročení se zaloguje, aby to šlo spravit.
|
||||
|
||||
## Spravedlivost mezi firmami
|
||||
|
||||
Z každé firmy se na jedno kolo vezme nejvýš jeden běh. Jedna firma s tisícem
|
||||
událostí tak nezablokuje ostatní - bez toho stačí jeden rozbitý e-shop
|
||||
a servicedesk stojí všem.
|
||||
|
||||
## Kroky, které děláme my
|
||||
|
||||
Založit ticket nebo přehodit ho na člověka není volání cizí služby, takže to
|
||||
nejde přes skript - sahá to do našeho úložiště. Pro uživatele je to v katalogu
|
||||
operace jako každá jiná.
|
||||
|
||||
| Krok | Co dělá |
|
||||
| --- | --- |
|
||||
| `ticket/upsert` | podle externího ID založí ticket, nebo na existující navěsí událost |
|
||||
| `ticket/assign-least-busy` | předá nejvolnějšímu ze skupiny, při shodě rozhoduje podíl ke kapacitě |
|
||||
| `ticket/set-type` | nastaví typ, za kterým stojí vlastní pole |
|
||||
| `ticket/set-stage` | posune do další fáze workflow daného typu |
|
||||
| `ticket/add-tags` | přidá štítky, existující nechá |
|
||||
| `ticket/set-status` | změní stav v životním cyklu |
|
||||
| `incident/create` | založí incident |
|
||||
| `flow/pause`, `flow/log` | pauza a zápis do logu |
|
||||
|
||||
## Tři osy na ticketu
|
||||
|
||||
| Osa | Kdo ji určuje | K čemu |
|
||||
| --- | --- | --- |
|
||||
| `status` | pevná čtveřice (nový, v řešení, čeká, vyřešeno) | životní cyklus, počítají se z něj statistiky a fronta |
|
||||
| `stage` | firma u typu ticketu (`TicketType.statuses`) | postup uvnitř typu: čeká na zabalení, předáno dopravci |
|
||||
| `tags` | kdokoliv, volně | označení, která spolu nemusí souviset |
|
||||
|
||||
Fáze může být **jen jedna**, proto se na ni dá spolehnout v podmínce. Přes
|
||||
štítky by to fungovalo taky, ale ticket by mohl mít "čeká na zabalení"
|
||||
i "expedováno" naráz a nikdo by nepoznal, co platí.
|
||||
|
||||
Fáze mimo workflow typu se odmítne. Překlep by jinak tiše vyřadil podmínku,
|
||||
která na fázi stojí.
|
||||
|
||||
## Živý dashboard
|
||||
|
||||
Dlaždice nad našimi daty se překreslí na událost ze streamu, tedy hned.
|
||||
|
||||
Data z konektorů ne: server je drží v mezipaměti podle `ttlSec` u widgetu.
|
||||
Přehled se po uplynutí té doby zeptá znovu a dokud je mezipaměť čerstvá,
|
||||
dostane ji zpátky bez volání cizí služby. U dlaždice je vidět stáří dat
|
||||
a tlačítko, které vynutí načtení znovu.
|
||||
|
||||
Bez mezipaměti by otevření přehledu znamenalo volání cizího API za každou
|
||||
dlaždici, a to má limity a někdy se za to platí.
|
||||
|
||||
## Ověřený scénář
|
||||
|
||||
Scénář jedné firmy: sklad (3 lidi), expedice (2), IT (3), typy ticketu
|
||||
objednávka a chyba, dvě automatizace.
|
||||
|
||||
1. Web pošle `{"kind":"order.created","data":{"order":{"id":"5001"}}}`.
|
||||
2. Webhook odpoví **202 za 12 ms**, nic nečeká.
|
||||
3. Worker založí ticket, dá mu typ objednávka a štítek čeká na zabalení.
|
||||
4. Změna ticketu spustí druhou automatizaci, ta podle typu a štítku předá
|
||||
práci **nejvolnějšímu ze skladu**.
|
||||
5. Druhá objednávka jde **jinému člověku**, protože první už jednu má.
|
||||
6. Chyba z převodníku dokladů přijde s vnořenou cestou `errors.0.message`,
|
||||
vznikne ticket typu chyba, dostane ho IT a **založí se incident**.
|
||||
|
||||
Ověřeno 19 kontrolami proti běžícímu serveru.
|
||||
|
||||
## Co zbývá
|
||||
|
||||
- **Víc instancí.** Výběr z fronty je v paměti jednoho procesu. Nad Postgresem
|
||||
to musí být `SELECT ... FOR UPDATE SKIP LOCKED`, jinak si dva workery
|
||||
vezmou tentýž běh. Místo je označené v `runtime/queue.ts`.
|
||||
- **Strop souběžných volání na dvojici firma a služba** a vypnutí služby po
|
||||
sérii chyb. Timeout a rozlišení "zkusit znovu / marné" už ve
|
||||
`scripts/http.ts` je.
|
||||
- **Dlouhé čekání** (pošli e-mail za tři dny) přes běh naplánovaný na později.
|
||||
Krok `flow/pause` umí nejvýš minutu, protože blokuje běh.
|
||||
@@ -2,6 +2,73 @@
|
||||
|
||||
Nejnovejsi nahore.
|
||||
|
||||
## 2026-08-13 - fronta, worker a spoustece
|
||||
|
||||
Popis v [20-fronta-a-runtime.md](20-fronta-a-runtime.md).
|
||||
|
||||
### Zmeneno zasadne
|
||||
|
||||
- **Webhook uz nic nevykonava v requestu.** Zapise udalost do fronty a odpovi
|
||||
202 do jednotek milisekund. Strom vykona worker na pozadi. Za konektory
|
||||
nerucime, takze cekat na cizi sluzbu v requestu znamena ztracet udalosti.
|
||||
|
||||
### Pridano
|
||||
|
||||
- `runtime/queue.ts`: fronta behu v ulozisti. Opakovani s rostouci prodlevou
|
||||
(30 s, 2 min, 10 min, hodina), spravedlive poradi po firmach, navrat
|
||||
zaseknutych behu po restartu, uklid hotovych.
|
||||
- `runtime/worker.ts`: bere praci z fronty, ctyri behy naraz.
|
||||
- `runtime/triggers.ts`: tri druhy spoustecu. Push (webhook), vnitrni udalost
|
||||
(vznik a zmena ticketu) a **pull, tedy pravidelne dotazovani** u sluzeb,
|
||||
ktere webhooky nemaji - posta, zpravy. Planovac jen rekne "je cas", samotny
|
||||
dotaz je prvni krok stromu.
|
||||
- **Kontrakt tela webhooku.** Kazdy parametr ma cestu (`data.order.id`,
|
||||
`errors.0.message`), takze jde napojit i odesilatel s vnorenym modelem.
|
||||
U adresy je videt metoda, ukazka tela podle parametru a kopiruje se cela
|
||||
adresa vcetne domeny.
|
||||
- Vnitrni kroky: `ticket/upsert` (zaloz nebo doplň podle externiho ID),
|
||||
`assign-least-busy`, `assign-by-external`, `set-type`, `set-stage`,
|
||||
`add-tags`, `set-status`, `incident/create`, `flow/pause`, `flow/log`.
|
||||
- **Faze ticketu** (`stage`) jako treti osa vedle stavu a stitku. Stav je
|
||||
zivotni cyklus a pocitaji se z nej statistiky, faze je workflow daneho typu
|
||||
a muze byt jen jedna, takze se na ni da spolehnout v podmince.
|
||||
- **ID z cizich aplikaci u resitele** (`externalIds`). Voicebot posle
|
||||
`voicebotId` a ticket skonci u toho, komu patri. Vazba je na jednom miste,
|
||||
ne v kazde automatizaci.
|
||||
- **Upozorneni**: komu prijde ticket, ten to vidi hned, vcetne cisla u zalozky.
|
||||
- **Incident z kazde chyby** se dvema urovnemi: `impact` cte klient a je
|
||||
srozumitelny, `detail` cte admin a je v nem cely beh, ktery krok selhal,
|
||||
cele hlaseni a data na vstupu. `detail` se vraci jen spravci platformy.
|
||||
- **Ochrana proti smycce.** Automatizace navazana na zmenu ticketu ticket
|
||||
meni, cimz se spousti znovu - pri vyvoji to server polozilo. Resi to
|
||||
oznaceni behu (`AsyncLocalStorage`) a strop peti behu na ticket za minutu.
|
||||
- Zivy dashboard: dlazdice nad nasimi daty se prekresli na udalost, data
|
||||
z konektoru drzi server podle `ttlSec` a jde vynutit nacteni znovu.
|
||||
|
||||
### Opraveno
|
||||
|
||||
- `path` a `intervalSec` u spoustece se pri ulozeni zahazovaly, takze kontrakt
|
||||
webhooku nefungoval.
|
||||
- Nad seznamem neslo pouzit `contains`, takze na stitky neslo postavit
|
||||
podminku. Prave na tom stoji prideleni prace.
|
||||
- Novejsi vystup kroku ted prekryje starsi se stejnym jmenem. Driv to builder
|
||||
hlasil jako konflikt i tam, kde zadny nebyl.
|
||||
- Marna chyba (chybejici skript, neexistujici skupina) se uz neopakuje petkrat.
|
||||
|
||||
### Overeno
|
||||
|
||||
Dva scenare proti bezicimu serveru, 34 kontrol celkem:
|
||||
|
||||
1. **Firma se skladem, expedici a IT.** Webhook odpovedel za 12 ms, worker
|
||||
zalozil ticket, dal mu typ a stitek, druha automatizace ho podle typu
|
||||
a stitku predala nejvolnejsimu ze skladu. Druha objednavka sla jinemu
|
||||
cloveku. Chyba z prevodniku dokladu prisla vnorenou cestou, skoncila u IT
|
||||
a zalozila incident.
|
||||
2. **Hovory z voicebota.** Telo `{callSid, status, voicebotId}`: callSid do
|
||||
externiho ID, status do faze, prirazeni podle voicebotId. Tri zpravy
|
||||
o tomtez hovoru daly **jeden ticket** se tremi udalostmi. Neznamy voicebot
|
||||
neskoncil tise - je videt ve fronte i jako incident.
|
||||
|
||||
## 2026-08-13 - runtime, prokliky z widgetu a kapacitni rozbor
|
||||
|
||||
### Pridano
|
||||
|
||||
Reference in New Issue
Block a user