Deep Dive in Hooks | Workflow SDK

VVercel
컴퓨터/소프트웨어창업/스타트업AI/미래기술

Transcript

00:00:00Hey, vielen Dank, dass Sie heute dabei sind.
00:00:02Ich bin Praneet vom Workflow-Team hier bei Vercel.
00:00:05Hi, ich bin Nate, ebenfalls aus dem Workflow-Team.
00:00:08Nate, du und ich sind von Anfang an im Workflow-Team dabei,
00:00:12und von all den Dingen, die wir in den letzten sechs Monaten veröffentlicht haben,
00:00:15sind Hooks und Webhooks meiner Meinung nach eines meiner Lieblings-Features,
00:00:18und genau darüber wirst du heute sprechen.
00:00:21Hooks und Webhooks sind auch mein Lieblings-Feature.
00:00:23Sie sind unglaublich leistungsfähig, und ich werde euch ein paar Demos zeigen, um zu erklären, warum.
00:00:28Die erste Demo ist etwas, das wir wahrscheinlich alle kennen: Magic Links.
00:00:33Ein Magic Link ist ein Login-Formular. Man gibt seine E-Mail ein, erhält eine E-Mail im Posteingang,
00:00:40und wenn man auf diesen Link klickt, ist man beim Dienst angemeldet.
00:00:44Ja, und wenn ich mich richtig erinnere, waren bei Vercel – eigentlich schon bevor es Vercel hieß,
00:00:48als es noch Zeit hieß – Magic Links die einzige Art der Authentifizierung,
00:00:52und wir haben dieses ganze System damals auch selbst gebaut.
00:00:56Das stimmt, und ich habe immer noch ein ETSD.
00:01:01Denn ohne Workflow ist die Implementierung eines solchen Systems viel komplizierter, als es auf den ersten Blick scheint.
00:01:08Die Logik ist am Ende über mehrere Dateien verstreut.
00:01:12Man braucht eine Datenbank, um den Status zu verfolgen, und es wird schnell unübersichtlich.
00:01:19Ja, ich habe schon darüber nachgedacht, wie ich das strukturieren würde und welche Datenbank ich nutzen würde,
00:01:24weil sich das wie ein bekanntes Problem anfühlt, für das ich schon früher Dinge gebaut habe.
00:01:28Also ja, ich würde gerne sehen, wie es aussieht.
00:01:30Ja, um zu demonstrieren, wovon ich spreche, die Schmerzpunkte, die ich meine,
00:01:38habe ich mit einer Art "traditionellen" Version eines Magic Link Logins ohne Workflow begonnen.
00:01:43Dabei sind drei Endpunkte beteiligt.
00:01:47Der erste ist, wenn das Login-Formular abgeschickt wird,
00:01:50und er muss eine Sitzung erstellen und diese in einer Datenbank, wie zum Beispiel Redis, speichern.
00:01:57Man muss eine TTL implementieren; man kann Daten nicht ewig herumliegen lassen, sie müssen ablaufen.
00:02:06Und dann das Senden der E-Mail – das könnte fehlschlagen, und dann funktioniert der Login nicht, was frustrierend ist.
00:02:14Richtig, und dann muss man einen Cron-Job haben oder einen Praktikanten, der die Datenbank aufräumt.
00:02:19Ich war damals vielleicht der Praktikant.
00:02:22Aber dann gibt es einen zweiten Endpunkt, der aufgerufen wird, wenn der Nutzer auf den Link in der E-Mail klickt.
00:02:28Dieser muss im Grunde die Datenbank abfragen und den Status wiederherstellen, der im ersten Endpunkt erstellt wurde.
00:02:36Und wir kommen hier schon zu echtem Spaghetti-Code.
00:02:38Als ich mir vorstellte, wie das aussehen würde, kam mir dieser Code so bekannt vor; so würde ich es auch strukturieren.
00:02:48Wir sehen, dass es schnell kompliziert wird, obwohl es ein sehr einfaches Konzept ist.
00:02:54Schauen wir uns also an, wie man dieses Feature in Workflow implementieren würde.
00:02:59Die Magic-Link-Implementierung mit dem Workflow-SDK sieht etwa so aus.
00:03:05Wir sehen hier unsere Funktion mit der "useWorkflow"-Direktive, was bedeutet, dass dies unsere Workflow-Funktion ist.
00:03:11Und als Erstes rufen wir die Funktion "createWebhook" auf, die aus dem Workflow-Paket stammt.
00:03:18Zudem nutzen wir in diesem Fall die Option "respondWithManual", was bedeutet, dass unsere Workflow-Funktion dafür verantwortlich ist,
00:03:36die Antwort auf die HTTP-Anfrage zu schreiben oder zu senden, die diesen Webhook auslöst.
00:03:40Und das ist dazu da, damit man danach einen Redirect oder ähnliches machen kann, wenn sie sich einloggen?
00:03:51Genau, falls es Informationen in unserer Workflow-Funktion gibt, die wir benötigen, um zu wissen, welche Antwort wir senden sollen.
00:03:57Ähnlich wie beim ersten Endpunkt senden wir die Login-E-Mail. Dies ist eine "useStep"-Funktion.
00:04:03Wenn also so etwas fehlschlägt, verfügt das Workflow-SDK über automatische Wiederholungsversuche.
00:04:10Der Aspekt der Dauerhaftigkeit bietet hier bereits einen Vorteil gegenüber dem traditionellen Ansatz.
00:04:21Also ist "sendLoginEmails" ein Schritt, und wenn die E-Mail fehlschlägt, wird sie mit derselben URL wiederholt,
00:04:26die man bereits für den Webhook erstellt hat. Und wenn wir hier schauen, ist das ein sehr interessantes Muster.
00:04:30Wir verwenden "promise.race" mit einem Sleep von fünf Minuten.
00:04:35Das ist möglich, weil dieses Webhook-Objekt ein Promise implementiert.
00:04:40Um auf die Anfrage dieses Webhooks zu warten, nutzt man einfach "await Webhook".
00:04:50Oder in diesem Fall macht man es mit dem Race. Das ist cool, weil ich eigentlich erwartet hätte,
00:04:58dass dieses Webhook-Feature einen Timeout oder eine Option als weiteres Argument hätte.
00:05:02Aber mir gefällt fast besser, dass es jetzt so viel sauberer ist: Für einen Timeout
00:05:06modelliert man es einfach als Race zwischen dem Webhook und einem Sleep.
00:05:12Ich habe das Gefühl, damit viel mehr machen zu können. Ich könnte vielleicht zwei verschiedene Webhooks gegeneinander antreten lassen.
00:05:16Man kann nicht viel machen, wenn man nur ein paar Argumente in einer Funktion hat.
00:05:21Aber die Tatsache, dass es nur ein Promise ist und ich ein "promise.race" gegen ein Sleep machen kann, vielleicht noch einen Schritt dazu...
00:05:23Ich liebe dieses Muster. Mein Kopf rattert schon bei all den Dingen, die ich damit bauen könnte.
00:05:28Richtig, und das ist das Schöne an den Primitiven, die das Workflow-SDK bietet.
00:05:33Alles wird als Promise bereitgestellt.
00:05:41Standard-JavaScript-Muster wie "await promise.race" funktionieren also einfach.
00:05:44Ein weiterer Punkt hier ist: Es gibt kein Redis. Es gibt keine Datenbank.
00:05:50Im traditionellen Beispiel haben wir Redis TTL verwendet, um diesen Timeout zu implementieren.
00:05:51In diesem Fall nutzen wir das Workflow-Sleep-Primitiv.
00:05:59Und auch keinen Praktikanten, der danach eine unordentliche Datenbank aufräumen muss.
00:06:07Das ist das Beste daran.
00:06:12Und so sieht man, dass der Workflow auf die öffentliche Anfrage mit einer Weiterleitung zur Erfolgsseite reagiert.
00:06:17Dann ruft er Informationen über den Nutzer ab, um sie an den Client zurückzugeben, der die Login-Seite aufgerufen hat.
00:06:24Das ist unser gesamter Workflow. Unsere Magic-Link-Implementierung besteht aus 50 Zeilen Code.
00:06:31Es ist unglaublich, das zu sehen. Können wir das in Aktion erleben?
00:06:41Hier ist unsere Magic-Link-Demo. Ich gebe einfach meine E-Mail-Adresse ein.
00:06:47Unser Workflow wurde gestartet und hat die E-Mail gesendet. Und da wartet jetzt ein Webhook.
00:06:52Tatsächlich ist unser Workflow gerade pausiert. Es wird also null Rechenleistung verbraucht,
00:06:57während man darauf wartet, dass der Mensch auf den Link in der E-Mail klickt.
00:07:02Oh, und wie sieht das auf Vercel aus? Kann ich einen laufenden Prozess sehen?
00:07:08Okay, wir haben die E-Mail erhalten. Bevor ich klicke, werfen wir einen Blick auf die Observability.
00:07:13Ich weiß, ich springe hin und her, aber ich finde es toll, dass wir uns das ansehen.
00:07:17Okay, wir sehen, dass unser Prozess hier ist und vor 40 Sekunden gestartet wurde.
00:07:25Wenn wir reinschauen, sehen wir die Standard-Observability-Features, die Workflow bietet.
00:07:39Wir sehen die Inputs für unseren Workflow-Lauf. Man sieht meine E-Mail-Adresse, die ich ins Formular eingegeben habe.
00:07:46Und interessanterweise sehen wir, dass unser Hook hier einfach wartet.
00:07:50Und du sagtest, es läuft gerade keine Rechenleistung. Das ist die Überwachung,
00:07:59aber es gibt nichts, was aktiv darauf wartet, dass ich auf diesen Hook klicke.
00:08:01Das ist richtig. Der Hook wartet, der Sleep schläft, und beides verbraucht tatsächlich keine Rechenleistung.
00:08:05Aber wir sehen unseren Hook, und falls ihr euch erinnert, beide befinden sich in einem "promise.race".
00:08:08Eines davon muss also zuerst fertig werden, damit der Workflow fortgesetzt wird.
00:08:11Wenn ich also auf diesen Link klicke... okay, wir sehen, dass ich zur Erfolgsseite weitergeleitet wurde,
00:08:17was einer der Schritte in unserer Workflow-Logik war.
00:08:27Und wenn ich zurück zum Login-Formular springe...
00:08:34Richtig, und auf dem Dashboard sollte das jetzt auch als abgeschlossen markiert sein.
00:08:41Stimmt. Unser Workflow wurde beendet.
00:08:59Und man sieht, dass auch der Timer stoppt, sobald der Hook gewonnen hat.
00:09:07Ja, wir konnten den Magic Link mit etwa 50 Zeilen Code implementieren.
00:09:10Das ist wirklich schick. Es ist toll zu sehen, wie – wenn man ein Whiteboard-Diagramm zeichnen müsste,
00:09:16Genau. Die "Create Webhook"-Funktion ist in diesem Sinne etwas abstrakter, da sie eine zufällig generierte, eindeutige Webhook-URL bereitstellt,
00:09:23die genau einem spezifischen Workflow-Lauf zugeordnet ist.
00:09:31In unserem GitHub- oder Slack-Webhook-Pfad könnte diese jedoch auf eine beliebige Anzahl von Workflow-Läufen verweisen.
00:09:36Richtig. Man muss etwas vorkonfigurieren, bei dem zwar mehrere Pull-Requests vorliegen, diese aber alle an denselben Endpunkt gehen.
00:09:49Und ich denke, das ist der leistungsstärkste Aspekt des Workflow-SDK: die Art und Weise,
00:09:54wie man seine Anwendungslogik logisch fließen lassen kann, anstatt sie mühsam an die Infrastruktur anzupassen.
00:10:04Richtig. Außerdem liebe ich die Idee mit den Webhooks hier – sie Webhook zu nennen,
00:10:07gibt mir eine ganz neue Denkweise über Webhooks.
00:10:14Es ist einfach diese flüchtige URL, die ich erstellen und bei der ich pausieren kann.
00:10:20Eigentlich ist das eine gute Überleitung, denn ich denke daran, dass wir bei Vercel viele dieser Agenten bauen.
00:10:28Wir bauen Slack-Agenten und GitHub-Agenten und abonnieren oft Webhooks von GitHub oder Slack, oder?
00:10:31Jedes Mal, wenn es einen neuen Kommentar in einem PR gibt und wir einen Vercel-Agenten starten wollen,
00:10:32wollen wir das basierend auf einem Event tun, für das GitHub diese Webhooks sendet, richtig?
00:10:35Können wir Workflow-Webhooks nutzen, um zum Beispiel Events von GitHub zu abonnieren?
00:10:40Okay, für so etwas wie einen Webhook von Slack oder GitHub muss man normalerweise manuell ins Dashboard gehen
00:10:47und eine statische Callback-URL konfigurieren.
00:10:52Stimmt. Man kann die nicht einfach einmalig erstellen; ich kann ihm keine Einmal-URL geben wie bei der E-Mail hier.
00:11:05Richtig. Das "createWebhook"-Feature ist in diesem Sinne etwas abstrakter, da es eine zufällig generierte,
00:11:09einzigartige Webhook-URL bereitstellt, die genau zu einem spezifischen Workflow-Lauf gehört.
00:11:13Im Fall unserer GitHub- oder Slack-Webhook-Route könnte das jedoch auf beliebig viele Workflow-Läufe verweisen.
00:11:17Richtig. Man muss etwas vorkonfigurieren, man hat zwar mehrere Pull Requests, aber sie gehen alle an denselben Endpunkt.
00:11:20Um das mit dem Workflow-SDK zu implementieren, gehen wir eine Ebene tiefer und nutzen das Low-Level-Hook-Primitiv.
00:11:26Dazu habe ich eine Demo vorbereitet.
00:11:28Schauen wir uns das mal an.
00:11:35Okay. Das hier ist der Storytime-Bot.
00:11:38Das ist die allererste Anwendung, die ich vor etwas mehr als einem Jahr mit dem Workflow-SDK geschrieben habe.
00:11:44Und so funktioniert's: Man tippt einfach den Befehl "storytime/" ein und wir sehen, wie dieser Thread erstellt wird.
00:11:50Jeder Thread wird durch einen einzelnen Workflow-Lauf repräsentiert.
00:11:53Wenn wir den Thread erweitern, sehen wir, dass ein LLM diese Geschichte für uns begonnen hat,
00:12:04und du oder ich oder wer auch immer in diesem Kanal ist, kann die Geschichte fortsetzen.
00:12:23Und das LLM hilft uns dabei, sie zu ihrem endgültigen Abschluss zu bringen.
00:12:27Okay. Luna hat einen magischen Samen, und was passiert als Nächstes? Sie pflanzt den Samen.
00:12:34Okay. Und wir sehen hier etwas Aktivität.
00:12:40Was passiert als Nächstes? Etwas Magisches.
00:12:55Unsere Geschichte ist fertig, wir haben ein Ende, und es wird auch ein kleines Bild dazu generiert.
00:13:04Aber wir springen darauf zurück.
00:13:10Ich bin schon sehr neugierig, denn mir ist aufgefallen, dass ich nur eine Webhook-Anfrage erwartet hatte,
00:13:14aber es waren mindestens zwei, weil du zwei Nachrichten hattest.
00:13:28Ich bin also gespannt, wie das im Code aussieht.
00:13:35Okay. Das hier ist die Workflow-Funktion für unseren Storytime-Bot.
00:13:44Wir sehen, dass sie die Channel-ID übernimmt, also den Kanal des Storytime-Bots.
00:13:58Man kann einige Konfigurationsoptionen übergeben.
00:14:04Aber interessanterweise sehen wir dieses "messages"-Array. Wenn ihr mit dem AI-SDK vertraut seid,
00:14:17ist das das Datenformat, in dem man seine KI-Konversation speichert.
00:14:29In einer typischen Slack-Bot-Anwendung, wie wir sie hier erstellt haben, würde man so etwas normalerweise
00:14:37in einer Datenbank speichern und bei jeder Iteration oder jedem Webhook-Event, wenn eine Nachricht
00:14:50in den Thread geschrieben wird, den Status wiederherstellen und die Konversation aus einer Datenbank abrufen.
00:14:59Und genau das passiert hier nicht. Das ist einfach nur ein Array in deiner Funktion.
00:15:07Ja. Das passt, denn ich musste vorhin schmunzeln, als ich im Intro diesen Kommentar sah:
00:15:13"Schau mal Mama, keine Queues oder KV."
00:15:20Und es gibt hier keinen Import für eine Datenbank. Du importierst nur Workflow.
00:15:28Und zurück zur Sache mit der letzten Nachricht: Das wird fast übersehen, aber du hast hier einfach eine Variable namens "finalStory",
00:15:35der wir im Laufe der Zeit Nachrichten hinzufügen werden, nehme ich an,
00:15:44und die finale Geschichte wird hier als String erscheinen, aber das muss in keine Datenbank.
00:15:50Es ist fast so, als wäre "let" hier deine Datenbank.
00:15:55Ja, "let is your database" ist ein toller Begriff, den wir prägen sollten.
00:16:06Den habe ich vielleicht von dir geklaut, aber...
00:16:11Das Interessante hier, worüber wir sprechen wollen, ist das Hook-Feature. Wir sehen, dass wir hier diesen Hook erstellen.
00:16:17Aber statt über eine feste Menge an Elementen oder einen Zeitstempel zu iterieren, nutzt du for await am Hook, und dieser Loop passt hier perfekt.
00:16:25also einen String, der Identifikationsmerkmale enthält, die für diesen Workflow-Lauf einzigartig sind.
00:16:33Das TS ist die Thread-ID. Dieser String ist also der Token, der diesen Workflow-Lauf eindeutig identifiziert.
00:16:42Wenn wir uns den Code für die Webhook-Route ansehen, sehen wir, dass die Event-Payload von Slack
00:16:46alle Informationen enthält, die wir brauchen, um diesen Identifier deterministisch wiederherzustellen.
00:16:50Und das ist die Magie, wie der Webhook wieder einem individuellen Workflow-Lauf zugeordnet wird.
00:17:01Ja, ich war neugierig wegen des Webhooks, denn beim Magic Link erstellst du neue URLs,
00:17:05aber da wir schon Slack-Bots gebaut haben, weiß ich: Man kann nicht für jeden Thread eine neue URL vergeben.
00:17:12Man muss es also so verstehen: Du hast eine API, die bereits mit Slack verbunden ist,
00:17:22aber jedes Mal, wenn du dort eine Nachricht erhältst, berechnest du auf der Empfängerseite denselben Token.
00:17:33Dein Workflow kann also im Grunde auf diesen Token warten, und du kannst denselben Token
00:17:42aus einer Nachrichten-Payload konstruieren, um diesen Workflow-Lauf fortzusetzen.
00:17:43Genau. Der Slack-Bot wurde einmalig manuell im Slack-Dashboard konfiguriert,
00:17:48und man muss statisch eine Webhook-Callback-URL definieren.
00:17:57Deshalb funktioniert das einfachere Hook-Primitiv hier besser, weil wir den Token dynamisch wiederherstellen können.
00:18:03Nur ein kurzer Blick: Das hier ist die Webhook-Route, und eigentlich passiert dort gar nicht so viel.
00:18:08Die Hauptsache ist, wie wir den Token aus den von Slack übergebenen Daten wiederherstellen.
00:18:12Und dann rufen wir die Resume-Funktion auf, was den Workflow-Lauf fortsetzt, der dazu gehört.
00:18:16Das ist wirklich cool. Und ich stelle mir eigentlich vor, dass es bei Webhooks ähnlich läuft.
00:18:23Erzeugt Webhook im Grunde nur einen zufälligen Token und du hast einen HTTP-Endpunkt, der genau diesen auflöst?
00:18:32Ja, nun, der Unterschied beim Webhook-Feature ist, dass man diese API-Route nicht selbst im Code definieren muss.
00:18:39Das Workflow-SDK implementiert tatsächlich eine Standard-Route für das Webhook-Feature für dich.
00:18:49Aber ansonsten ist es ein zufällig generierter Token, der für einen spezifischen Workflow-Lauf einzigartig ist.
00:18:52In diesem Fall haben wir unseren Hook mit dem Token und – zurück zu etwas, das du vorhin erwähnt hast –
00:18:56dieser Hook kann Daten mehrfach empfangen. Das unterscheidet ihn vom Magic-Link-Beispiel,
00:18:58das nur ein einziges Mal ausgelöst werden musste.
00:19:05Hier möchten wir, dass der Hook bei jeder neuen Nachricht feuert, die jemand in den Slack-Thread schreibt.
00:19:10Dazu nutzt man die "for await"-Syntax in JavaScript, die bei Async-Iteratoren üblich ist.
00:19:14In diesem Fall empfangen wir über unseren Hook mehrere Event-Payloads vom Slack-Webhook.
00:19:16Das ist so cool. Ich habe nie einen wirklich guten Anwendungsfall für... ich liebe Async-Iteratoren und Generatoren
00:19:25und habe vor langer Zeit sogar einen Vortrag darüber gehalten. Aber sie waren immer nur gut für Demos.
00:19:34Hier liest es sich für mich wie eine ganz einfache Schleife.
00:19:40Aber anstatt über eine feste Liste oder einen Zeitstempel zu iterieren, nutzt du "for await" auf dem Hook.
00:19:42Hier ist eine Schleife, die perfekt passt: Alles innerhalb der Schleife entspricht einer Nutzernachricht.
00:19:43Das ist eine schöne Art, darüber nachzudenken: Eine neue Nutzernachricht führt zu einer weiteren Iteration dieser Schleife,
00:19:54alles wird eingereiht und läuft weiter.
00:19:55Das Schöne daran ist: Während wir bei jeder Iteration darauf warten, dass der Nutzer die nächste Nachricht tippt,
00:20:02wird absolut keine Rechenleistung verbraucht.
00:20:05Der Workflow ist komplett pausiert, und die nächste Nachricht im Thread könnte in Minuten oder Tagen
00:20:06oder vielleicht auch nie ankommen – und das ist völlig in Ordnung.
00:20:17Es gibt also wahrscheinlich Slack-Threads in diesem Kanal mit dem Slackbot, wo ich jetzt zurückgehen könnte
00:20:32und da wartet seit zwei Wochen immer noch ein Prozess, weil niemand geantwortet hat.
00:20:41Sie können also ein NPM-Paket ausliefern.
00:20:51Sandbox liefert im Grunde nur ein NPM-Paket aus, das die Direktive "use Step" innerhalb dieser Funktion verwendet.
00:20:56Wenn Sie es also importieren und in einem Workflow verwenden, wird Sandbox automatisch zu einem Step, ohne dass Sie diesen Code schreiben müssen.
00:21:00Das ist so cool. Und ich sehe, du nutzt weitere "promise.all", um Schritte dazwischen zu parallelisieren.
00:21:09Dieser Vorgang ist also ein Step.
00:21:12Sie können also ein NPM-Paket ausliefern.
00:21:15Sandbox liefert im Grunde ein NPM-Paket aus, das die Direktive "use Step" in dieser Funktion enthält.
00:21:21Wenn Sie es in einen Workflow importieren, wird Sandbox automatisch zum Step, ohne dass Sie Code schreiben müssen.
00:21:29Das bedeutet nicht, dass man Sandbox nicht auch außerhalb eines Workflows nutzen kann.
00:21:32Was passiert, wenn man es ohne Workflow aufruft?
00:21:35Wenn man bedenkt, dass die Direktive nur ein String ist: Ohne Workflow-Compiler bewirkt dieser String nichts.
00:21:47Es funktioniert also einfach.
00:21:49Das Hinzufügen von "use Step" in NPM-Paketen klappt auch ohne Workflow-SDK wunderbar.
00:21:55Sobald man die Funktion im Workflow-SDK nutzt, erhält man sofort die Vorteile der Beständigkeit.
00:22:03Okay, die Sandbox macht also die üblichen Dinge.
00:22:07Sie installiert FFmpeg, da das standardmäßig nicht verfügbar ist.
00:22:11Sie lädt die URL einer Datei herunter, die wir angeben.
00:22:14Und jeder dieser Durchläufe ist aktuell auch ein Step?
00:22:17Ja, diese führen einzelne Befehle in der Sandbox aus und das sind Steps. Wir werden sie im Monitoring sehen.
00:22:29Alles klar, verstehe. Das ist cool. Ich habe schon ein wenig vorausgeschaut und bemerkt, dass es ein "AND" bei diesem Lauf gibt.
00:22:36In diesem Fall übergeben wir die Webhook-URL an unser Bash-Skript, das in der Sandbox läuft.
00:22:43Hier wird FFmpeg ausgeführt und die Datei in das Format konvertiert, das wir in der UI auswählen.
00:22:53Wenn das fertig ist, führt das Bash-Skript einen cURL-Befehl gegen unsere Webhook-Callback-URL aus.
00:22:59Sobald dieser cURL-Request erfolgt, wird unsere Workflow-Logik fortgesetzt.
00:23:04Alles klar. Ich habe schon etwas vorausgeschaut und gesehen, dass bei diesem Durchlauf ein "AND" steht.
00:23:11Sie lassen das Skript also im Hintergrund laufen, weil so ein FFmpeg-Step viel länger dauern könnte.
00:23:17Man will keinen Step, der einfach nur dastsitzt und wartet.
00:23:20Richtig. Genau diese Zeile hier startet unser FFmpeg-Konvertierungsskript im Hintergrund.
00:23:28Danach wird die Workflow-Funktion pausiert und wir warten darauf, dass der Webhook fortgesetzt wird.
00:23:34Und ich sehe wieder das "Promise.race" mit einer Stunde Sleep. Das ist ein cooles Muster.
00:23:40Genau, denn der FFmpeg-Prozess kann diesmal lange dauern.
00:23:46Es könnte eine sehr große Mediendatei sein. Deshalb legen wir hier ein Timeout von einer Stunde fest.
00:23:51Das ist völlig okay. Im Workflow kann man quasi unbegrenzt lange schlafen.
00:23:56Und wieder verbraucht es null Rechenleistung, während wir auf die Fortsetzung des Webhooks warten.
00:24:01Können wir uns das ansehen? Haben wir dazu eine Demo?
00:24:04Haben wir.
00:24:05Es ist ein etwas albernes Beispiel.
00:24:07Ja, ich habe das "Big Buck Bunny"-Beispiel sofort wiedererkannt. Das ist von Blender.
00:24:12Ja, ich erinnere mich, dass ich diese Videos gesehen habe, als ich vor langer Zeit Blender gelernt habe.
00:24:16Oh wow, ich bin neidisch.
00:24:19Wir haben die URL der Mediendatei eingefügt. In diesem Fall extrahieren wir nur die Audiospur.
00:24:26Sobald wir den Button klicken, startet der Workflow und wir können zum Monitoring rübergehen.
00:24:33Oh, da ist er ja. Hier sehen wir unsere Sandbox-Erstellung.
00:24:37Und das gibt unsere Sandbox-Instanz zurück. Ziemlich cool.
00:24:42Das liegt daran, dass im Workflow alles serialisierbar sein muss.
00:24:46Aber wie du sagtest: Sandboxes implementieren Serialisierung. Sie sind also im Workflow serialisierbar.
00:24:53Genau. Das Vercel Sandbox NPM-Paket hat eine Sandbox-Klasse, die die Workflow-Serialisierungsfunktionen nutzt.
00:25:03Dadurch funktioniert es einfach in unserem Monitoring.
00:25:06Das kann also jedes Paket machen, oder? Nicht nur Sandbox. Jede Klasse kann diese Symbole nutzen.
00:25:17Ganz genau. Wir sehen, dass unser Hook diesmal nach 20 Sekunden zurückgerufen wurde.
00:25:25Die Konvertierung ging recht schnell, da die Datei klein ist, aber es hätte jede beliebige Zeit sein können.
00:25:31Nachdem die Sandbox erstellt war, wurde der Hook generiert und an die Sandbox für FFmpeg übergeben.
00:25:43Als das fertig war, haben wir ein Payload von unserer Sandbox erhalten.
00:25:48Das ist der cURL-Befehl aus dem Bash-Skript. Er nutzt cURL in der Sandbox, um den Webhook abzuschließen.
00:25:57Richtig. Unsere Sandbox ist mit der Arbeit fertig und übergibt die Kontrolle zurück an den Workflow.
00:26:04Ich sehe das jetzt so: Bei Steps im Workflow führt man Code im Hintergrund aus und macht dann weiter.
00:26:13Aber Hook und Webhook fühlen sich nach einer tieferen Ebene an. Ich erstelle eine URL und warte auf alles.
00:26:21Das kann ein Magic Link, eine E-Mail oder eine Sandbox sein. Was auch immer passieren muss.
00:26:27Der Workflow pausiert mit seinem gesamten Status, bis das Ereignis eintritt. Das wirkt fast tieferliegender als ein Step.
00:26:34Ja. Für mich sind Webhook und Hook Wege, um externe Payloads in den Workflow zu bringen.
00:26:42Ich sehe es so: Ein Step lässt den Workflow pausieren, um auf den Abschluss einer Berechnung zu warten.
00:26:50Aber Hook und Webhook wirken noch fundamentaler, weil man einfach einen Token oder eine URL erstellt.
00:27:01Man kann sie an einen Menschen, per E-Mail oder an einen anderen Workflow senden.
00:27:05Sobald das erledigt ist, wacht der Haupt-Workflow auf und macht genau dort weiter, wo er aufgehört hat.
00:27:12Es ist also noch grundlegender als ein Step – eine Art, den Workflow für jede externe Aktion zu pausieren.
00:27:19Ja. Ein Hook ist die Möglichkeit, auf ein externes Payload zu warten, das in den Workflow zurückfließt.
00:27:31Das ist echt cool. Unsere Zeit ist um, aber diese Demos haben mir gezeigt, warum Hook mein Lieblingsfeature ist.
00:27:42Klasse. Es freut mich sehr, dass es dir gefallen hat.

Key Takeaway

Das Workflow SDK ersetzt komplexe Infrastruktur wie Redis-Datenbanken und Cron-Jobs durch statusbehaftete JavaScript-Primitive wie Promises und Async-Iteratoren, die externe Ereignisse direkt in den Programmfluss integrieren.

Highlights

  • Das Vercel Workflow SDK ermöglicht die Implementierung von Magic Links in etwa 50 Zeilen Code ohne externe Datenbanken wie Redis.

  • Webhooks und Hooks pausieren Workflows ohne jeglichen Rechenleistungsverbrauch, während sie auf externe Ereignisse oder menschliche Interaktionen warten.

  • Die createWebhook-Funktion mit respondWithManual erlaubt es dem Workflow, direkt die HTTP-Antwort für den auslösenden Webhook zu steuern.

  • Durch promise.race zwischen einem Webhook-Promise und einem Sleep-Primitiv lassen sich Timeouts für asynchrone Prozesse ohne Cron-Jobs realisieren.

  • Das Hook-Primitiv ermöglicht über Async-Iteratoren (for await) die Verarbeitung mehrerer aufeinanderfolgender Ereignisse innerhalb eines einzigen Workflow-Laufs.

  • NPM-Pakete wie Vercel Sandbox nutzen die useStep-Direktive, um Funktionen automatisch als persistente Workflow-Schritte zu registrieren.

Timeline

Probleme traditioneller Magic-Link-Implementierungen

  • Traditionelle Systeme verteilen die Logik über mehrere Dateien und benötigen eine Datenbank zur Statusverfolgung.
  • Die Implementierung von Timeouts erfordert Redis TTLs oder manuelle Bereinigungsprozesse durch Cron-Jobs.
  • Fehlgeschlagene E-Mail-Versandvorgänge führen ohne zusätzliche Abstraktionen zum Abbruch des Login-Prozesses.

Ein herkömmlicher Login-Prozess umfasst mindestens drei Endpunkte: Formularübermittlung, Sitzungserstellung in Redis und Link-Verifizierung. Diese Struktur führt oft zu unübersichtlichem Spaghetti-Code, da der Status zwischen den Anfragen manuell wiederhergestellt werden muss. Ohne Workflow-Management ist die Fehlerbehandlung bei externen Diensten wie E-Mail-Providern fehleranfällig.

Magic Links mit Workflow-Webhooks

  • Die Funktion useWorkflow markiert den Einstiegspunkt für persistente Logik ohne externe Infrastruktur.
  • Eingebaute Wiederholungsmechanismen in useStep sichern den E-Mail-Versand gegen temporäre Fehler ab.
  • Das Webhook-Objekt fungiert als natives Promise, das auf eine HTTP-Anfrage wartet.

In der Workflow-Variante wird eine eindeutige Webhook-URL generiert, die direkt einem spezifischen Prozess zugeordnet ist. Ein Promise.race zwischen dem Webhook und einer Sleep-Funktion von fünf Minuten ersetzt die Redis TTL Logik vollständig. Während der Workflow auf den Klick des Nutzers wartet, wird er pausiert und verbraucht keine Cloud-Ressourcen.

Zustandslose Observability und Monitoring

  • Das Vercel Dashboard visualisiert den aktuellen Status pausierter Hooks und deren Inputs in Echtzeit.
  • Workflows bleiben über Tage oder Wochen im Pausenzustand erhalten, ohne aktive Rechenleistung zu binden.
  • Nach Abschluss eines Hooks stoppen konkurrierende Timer im selben Race-Bedingungs-Block automatisch.

Die Observability-Features zeigen detailliert, welcher Schritt gerade ausgeführt wird oder worauf der Prozess wartet. Im Dashboard sind Eingabedaten wie E-Mail-Adressen sichtbar, während der Hook-Status als wartend markiert bleibt. Sobald der Nutzer den Link klickt, wird die Ausführung an der exakten Stelle im Code fortgesetzt.

Multi-Event-Steuerung mit Hooks am Beispiel eines Slack-Bots

  • Ein String-Token identifiziert Workflow-Läufe deterministisch anhand von Thread-IDs aus Slack-Payloads.
  • Variablen innerhalb der Workflow-Funktion dienen als persistenter Speicher über den gesamten Konversationsverlauf.
  • Async-Iteratoren ermöglichen das Empfangen mehrerer Nachrichten innerhalb einer for-await-Schleife.

Der Storytime-Bot speichert die gesamte Konversation in einem einfachen lokalen Array statt in einer Datenbank. Durch die Verwendung des Hook-Primitivs kann der Workflow auf spezifische Token reagieren, die aus eingehenden Webhooks berechnet werden. Dies erlaubt es, komplexe, mehrstufige Interaktionen wie KI-generierte Geschichten in einer einzigen linearen Funktion abzubilden.

Integration externer Systeme und Sandbox-Umgebungen

  • Das Workflow SDK unterstützt die Serialisierung ganzer Klassen wie Vercel Sandbox Instanzen.
  • Hintergrundprozesse wie FFmpeg-Konvertierungen werden über cURL-Aufrufe an den Webhook-Endpunkt zurückgemeldet.
  • Bibliotheken können die useStep-Direktive intern nutzen, um ohne zusätzlichen Code persistent zu werden.

Am Beispiel einer Videokonvertierung mit FFmpeg wird gezeigt, wie langwierige Hintergrundaufgaben integriert werden. Der Workflow startet ein Bash-Skript in einer isolierten Sandbox, generiert einen Webhook und pausiert für bis zu eine Stunde. Das Skript meldet den Abschluss via cURL an die flüchtige URL, woraufhin der Workflow mit dem Ergebnis aufwacht.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video