Doručování webhooků
Vytvořili jste skupinu úloh a během milisekund dostali odpověď 202. Překlady teď běží na pozadí, jedna úloha pro každý jazyk. Můžete dotazovat stav každé úlohy, dokud neskončí – ale nejspíš nechcete rozjíždět polling smyčku jen proto, abyste zjistili, že němčina už je hotová. Chcete, aby se váš server dozvěděl o každém hotovém jazyku hned v tu chvíli.
Přesně k tomu webhook slouží. Když při vytváření úloh předáte callbackUrl, Lingo odešle výsledek metodou POST na tuto URL, jakmile každá úloha dosáhne koncového stavu – jeden POST pro každý jazyk, přesně ve chvíli, kdy je hotový. Jazyk, který se přeloží bez problémů, dorazí jako translation.completed s daty. Jazyk, jehož překlad selže, dorazí jako translation.failed s chybou. Ať tak nebo tak, dostanete informaci pro každý jazyk, aniž byste se museli ptát.
Na této stránce najdete oba typy payloadů i to, jak s nimi pracovat. Doručení je podepsané a opakovaně se doručuje – tenhle mechanismus je sdílený s provisioningem a je popsaný na stránce ověření podpisu webhooku, na kterou odkazujeme všude tam, kde ji budete potřebovat.
Na této stránce
- Jak doručování funguje
- Payload completed
- Payload failed
- Zpracování webhooku
- Kdy není doručování ten správný nástroj
Jak doručování funguje#
Každý jazyk ve skupině je samostatná úloha. Ve chvíli, kdy některá z nich dosáhne koncového stavu, se její výsledek samostatně doručí na vaši callbackUrl – Lingo nečeká na nejpomalejší jazyk a neslučuje celou skupinu do jediného volání. Čtrnáct cílových jazyků znamená až čtrnáct POST požadavků, které přicházejí podle toho, kdy je který jazyk hotový, v pořadí, v jakém se dokončí.
Při vytváření skupiny úloh nastavte cílovou adresu pomocí callbackUrl. Platí pro všechny úlohy v dané skupině a každá skupina má vlastní nastavení — v řídicím panelu pro to žádná volba není. Pokud ho nevyplníte, nic se neodešle: výsledky zůstanou u úlohy, dokud si je nevyzvednete.
Opakovaný pokus, který znovu použije idempotencyKey, vrátí původní skupinu a doručování bude dál pokračovat do callbackUrl, se kterým byla tato skupina vytvořena — jiná adresa HTTPS URL v opakovaném pokusu se ignoruje.
Pouze HTTPS
callbackUrl musí používat HTTPS. HTTP URL se při vytváření úlohy odmítne s chybou 400 – webhook je podepsaný a posílat podepsaný payload přes nešifrovaný přenos by popíralo smysl.
Přes síť putují dva typy payloadu, které rozlišíte podle pole type: translation.completed a translation.failed. Oba uvádějí úlohu i skupinu, do které patří, a také jazyk, kterého se týkají, takže jeden handler může routovat podle type a aktualizovat správný záznam.
Neznámé typy událostí zpracovávejte bezpečně
Dnes se přenášejí translation.completed a translation.failed. Berte tu množinu jako otevřenou – větvěte jen podle typů, které znáte, a ostatní ignorujte, aby budoucí typ události nemohl rozbít už nasazený handler.
Payload completed#
Když úloha úspěšně skončí, payload obsahuje přeložené data – ve stejném tvaru, jaký byste dostali při načtení úlohy, jen vám dorazí automaticky místo toho, abyste je zjišťovali pollingem. data kopíruje strukturu, kterou jste odeslali: každý řetězec je přeložený, každá neřetězcová hodnota (čísla, booleany, null) zůstává zachovaná a vnoření se nemění.
{
"type": "translation.completed",
"jobId": "ljb_A1b2C3d4E5f6G7h8",
"groupId": "ljg_A1b2C3d4E5f6G7h8",
"sourceLocale": "en",
"targetLocale": "de",
"data": {
"id": "course_101",
"title": "Einführung in maschinelles Lernen",
"steps": [
{ "heading": "Was ist ML?", "body": "Maschinelles Lernen ist ein Teilbereich der künstlichen Intelligenz." },
{ "heading": "Überwachtes Lernen", "body": "Trainieren eines Modells mit gelabelten Daten." }
],
"metadata": { "author": "Dr. Smith", "difficulty": "beginner" }
}
}| Pole | Popis |
|---|---|
type | translation.completed |
jobId | Úloha, která skončila (prefix ljb_) |
groupId | Skupina, do které patří (prefix ljg_) |
sourceLocale | Zdrojový jazyk, který jste odeslali |
targetLocale | Jazyk, do kterého byl tento payload přeložen |
data | Přeložený obsah odpovídající struktuře data, kterou jste odeslali |
Úloha, která vytvoří výstup, není selhání – takže úloha, která skončila jako completed_with_warnings (výstup byl vytvořen, ale jedna nepovinné fáze pipeline neproběhla), se doručí jako translation.completed s použitelnými data. Webhook vám říká, že je jazyk připravený; varování k jednotlivým krokům, která vysvětlují, proč k tomu došlo, najdete u jedné úlohy, kterou si načtete podle jobId, když je budete potřebovat.
Payload failed#
Překlad do některého jazyka může selhat – model může vypršet na timeoutu, všechny nakonfigurované modely mohou být nedostupné. Když úloha dosáhne stavu failed, stejně o tom dostanete informaci. Typ payloadu je translation.failed a místo data obsahuje řetězec error:
{
"type": "translation.failed",
"jobId": "ljb_C3d4E5f6G7h8I9j0",
"groupId": "ljg_A1b2C3d4E5f6G7h8",
"sourceLocale": "en",
"targetLocale": "ja",
"error": "Model timeout after 30 seconds"
}| Pole | Popis |
|---|---|
type | translation.failed |
jobId | Úloha, která selhala |
groupId | Skupina, do které patří |
sourceLocale | Zdrojový jazyk, který jste odeslali |
targetLocale | Jazyk, který selhal |
error | Lidsky čitelný popis selhání |
Selhání se týká jen jednoho jazyka. Pokud jste odeslali de, fr a ja, selhání ja dorazí jako samostatný POST typu translation.failed, zatímco de a fr přijdou jako translation.completed – německý i francouzský překlad se doručí bez ohledu na to. Stav skupiny partial-failure status tuhle kombinaci odráží. Pokud chcete selhaný jazyk obnovit, odešlete novou úlohu jen pro tento jazyk s novým klíčem idempotence.
Zpracování webhooku#
První myšlenka skeptického čtenáře je tady správná: můj handler dělá skutečnou práci – zápis do databáze, pročištění cache, rozeslání připojeným klientům – tak to přece neudrží spojení otevřené tak dlouho, až webhook timeoutne?
Ano, proto na to Lingo nenechávejte čekat. Nejprve vraťte 200, zpracování nechte až na potom. Přijetí potvrďte okamžitě a skutečnou práci udělejte až po odeslání odpovědi. Handler, který vrací odpověď rychle, udržuje doručování zdravé; handler, který blokuje na navazující práci, si zbytečně říká o retry.
app.post("/webhooks/translations", verifyWebhook, async (req, res) => {
// Acknowledge first - one POST per locale, the moment it lands.
res.status(200).send("ok");
const { type, jobId, groupId, targetLocale, data } = req.body;
if (type === "translation.completed") {
await db.content.update({
where: { groupId },
data: { [`content_${targetLocale}`]: data },
});
// Advance your own progress model - your UI can poll this or receive it over SSE.
await db.translationProgress.increment({
where: { groupId },
data: { completedLanguages: { increment: 1 } },
});
}
if (type === "translation.failed") {
console.error(`Translation failed: ${jobId} (${targetLocale})`, req.body.error);
}
});Middleware verifyWebhook je jediná část, kterou tato stránka nedefinuje. Každé doručení je podepsané podle specifikace Standard Webhooks, takže nejde o schéma, které byste museli složitě rozebírat. Jak ověření provést – a jak vypadá plán opakování po ne-2xx odpovědi – je plně zdokumentované na stránce ověření podpisu webhooku, sdílené s provisioningem. Zapojte tenhle middleware dřív, než začnete payloadu důvěřovat: neověřené tělo požadavku je neautentizované.
Než začnete tělu požadavku věřit, ověřte podpis
Váš endpoint je veřejná URL; kdokoli na ni může poslat POST. Než s jakýmkoli payloadem začnete pracovat, ověřte podpis proti surovému tělu požadavku. Jak na to – hlavičky, HMAC i secret whsec_ – najdete na stránce ověření podpisu.
Kdy není doručování ten správný nástroj#
Webhook je pohodlný push mechanismus, ne zdroj pravdy. Ve dvou případech je lepší sáhnout po něčem jiném – a obojí je jen o jeden klik vedle.
Pokud byl váš endpoint v okamžiku doručení výsledku nedostupný, platforma to zkusí znovu – a i když se vyčerpají všechny pokusy, výsledek se neztratí. Pořád zůstává k dispozici přes jobId; callbackStatus úlohy zaznamenává, jestli se push nakonec podařil. Samotný plán opakování najdete na stránce podpis a doručování. Webhook vám v běžném případě ušetří polling smyčku; v tom méně běžném je pod ním vždycky k dispozici záznam úlohy.
A pokud chcete živý průběh v UI – čítač, který se mění z 3 z 14 na 4 z 14 podle toho, jak jednotlivé jazyky dokončují, místo callbacku pro každý jazyk na váš server – pak potřebujete WebSocket pro skupinu úloh, ne webhook.