Deno Queues
(deno.com)- Deno Queues ist eine serverlose verteilte Queue auf Basis von Deno KV, mit der sich lang laufende Aufgaben asynchron auslagern oder Ausführungen für einen späteren Zeitpunkt planen lassen
- Entwickler können Nachrichten mit
.enqueue()einreihen und sie mit.listenQueue()verarbeiten, ohne separate Queue-Infrastruktur einzurichten oder zu betreiben - Lokal wird SQLite verwendet, auf Deno Deploy FoundationDB; Deploy startet zum Zeitpunkt der Nachrichtenverarbeitung bei Bedarf ein V8 isolate und führt es aus
- Die Zustellung erfolgt per at-least-once delivery, daher kann dieselbe Nachricht bei Fehlern oder Wiederholungen mehrfach verarbeitet werden
- Es gibt keine separate Queue-Abrechnung, aber enqueue zählt als KV-Schreibvorgang, der Nachrichtenempfang als KV-Schreibvorgang plus Deno-Deploy-Request; daher sollten doppelte Verarbeitung und Kostenstruktur gemeinsam berücksichtigt werden
Wofür Deno Queues zuständig ist
- Deno Queues ist eine Queue-Funktion auf Basis von Deno KV, mit der Anwendungen einen Teil ihrer Verarbeitung als asynchrone Aufgabe auslagern oder Aufgaben für eine spätere Ausführung planen können
- Deno zielt darauf ab, wiederkehrende Einrichtung und Infrastrukturkonfiguration in der Cloud-Softwareentwicklung zu reduzieren und Entwicklern grundlegende Bausteine bereitzustellen, mit denen sie schneller entwerfen, verbessern und veröffentlichen können
- Deno KV ist eine Persistenzoption auf Basis von FoundationDB und befindet sich derzeit in der offenen Beta
- Queues stellt auf Deno KV skalierbares Messaging und Verwaltung für Hintergrundverarbeitung bereit
Basis-API und Ausführungsmodell
- Die Kern-API von Deno Queues besteht aus zwei Teilen
.enqueue(): legt eine neue Nachricht in die Queue und sorgt dafür, dass sie sofort oder zu einem späteren Zeitpunkt zugestellt wird.listenQueue(): dient als Handler, der neue Nachrichten aus der Queue empfängt und verarbeitet
- Der grundlegende Ablauf besteht darin, KV mit
Deno.openKv()zu öffnen, inlistenQueueeine Slack-Nachricht zu senden und beienqueuemit{ delay: 60000 }festzulegen, dass die Verarbeitung nach 60 Sekunden erfolgen soll - Je nach Ausführungsumgebung wird ein anderer Speicher verwendet
- Bei lokaler Ausführung SQLite
- Bei Ausführung auf Deno Deploy FoundationDB
- Auf Deno Deploy startet zur möglichen Verarbeitungszeit einer Nachricht bei Bedarf ein V8 isolate und dispatcht die Nachricht
- Der Anwendungscode muss lediglich im
listenQueue-Handler neue Nachrichten empfangen; die übrige Ausführungsverwaltung übernimmt Deno Deploy
Zustellgarantien und Wiederholungen
- Deno Queues garantiert at-least-once delivery
- Die meisten per enqueue eingereihten Nachrichten rufen den
listenQueue-Handler nur einmal auf, in manchen Fehlersituationen kann derselbe Handler zur Einhaltung der Zustellgarantie jedoch mehrfach aufgerufen werden - Daher muss die Anwendung doppelte Nachrichtenverarbeitung sicher handhaben
- Wenn der
listenQueue-Handler eine Exception wirft, versucht die Runtime den Aufruf automatisch erneut - Wiederholungen laufen weiter, bis der Aufruf erfolgreich ist oder die maximale Anzahl an Wiederholungen erreicht ist; der aktuelle Standardwert liegt bei 5
- Nachrichten, die die maximale Anzahl an Wiederholungen erreicht haben, werden gelöscht
Nutzung zusammen mit KV atomic transactions
- Deno Queues kann mit KV atomic transactions kombiniert werden
- Wird eine Nachricht als Teil einer KV-Transaktion eingereiht, gelangt sie nur dann in die Queue, wenn die gesamte Transaktion erfolgreich ist
- Ein Beispielablauf prüft und aktualisiert die Kontostände von Bob und Liz und reiht anschließend Benachrichtigungen an beide ein
- Der Zustand wird mit
check(bob, liz)geprüft - Bobs Kontostand wird verringert und Liz’ Kontostand erhöht
- Mit
enqueuewerden jeweils Benachrichtigungen für Liz und Bob hinzugefügt - Erst wenn
commit()erfolgreich ist, werden alle Änderungen und das enqueue wirksam
- Der Zustand wird mit
- Auch innerhalb des
listenQueue-Handlers kann der Zustand in Deno KV aktualisiert werden - Um Updates pro Nachricht nur einmal auszuführen, lässt sich ein Ablauf zur Vermeidung doppelter Verarbeitung aufbauen, bei dem ein Nonce gespeichert und gelöscht wird
- Beim enqueue wird ein Nonce mitgespeichert
- Wenn bei der Verarbeitung kein Nonce vorhanden ist, wird sofort zurückgegeben
- Bei erfolgreicher Verarbeitung wird der Nonce gelöscht und Zähler- sowie Kontostandszustand werden gemeinsam aktualisiert
Geeignete Einsatzfälle für Queues
- Queues sind nützlich für die Skalierung von Anwendungen, weil sie Servern ermöglichen, asynchrone Verarbeitung auszulagern und zukünftige Aufgaben zu planen
-
Geplante E-Mail-Benachrichtigungen
- Wenn eine vom Nutzer gestartete Aufgabe lange dauert oder nicht auf eine Abschlussantwort gewartet werden muss, kann sie in eine Queue ausgelagert werden, um die Reaktionsfähigkeit des Servers oder der App zu erhalten
- Im Beispiel wird eine
welcome_email-Nachricht sofort eingereiht, während einesurvey_email-Nachricht mit{ delay: 259200000 }verzögert ausgeführt wird
-
Zuverlässige Webhook-Verarbeitung
- Wenn Webhook-Requests nicht direkt verarbeitet, sondern in eine Queue gelegt werden, lassen sich Antwort und eigentliche Verarbeitung trennen
- Mit Oak und Queues wird bei einem POST-Request an
/webhookder Request-Body in die Queue gelegt und HTTP 200 zurückgegeben - Die eigentliche Webhook-Verarbeitung erfolgt asynchron in
listenQueueüberprocessWebHook
-
Slack- und Discord-Bots
- Queues kann auch zum Erstellen von Discord- oder Slack-Bots verwendet werden
- Das Beispiel einer Slack reminder app zeigt, wie sich mit Deno Queues eine einfache Slack-Reminder-App bauen lässt
- Das Beispiel eines Discord bot erstellt mit Deno Queues ein Giveaway und ermöglicht Nutzern die Teilnahme mit einem Klick
- Weitere Beispiele für die Nutzung von Queues finden sich auf docs.deno.com
Abrechnungsmodell
- Für Deno Queues gibt es keinen separaten dedizierten Abrechnungsposten
- Die Kosten werden auf Basis von Deno-KV-Operationen und Deno-Deploy-Requests berechnet
- Nachricht enqueue: Jeder enqueue-Vorgang entspricht einem KV-Schreibvorgang
- Nachrichtenempfang: Für jede empfangene Nachricht fallen ein KV-Schreibvorgang und eine Request-Gebühr an
- Abgerechnet werden nur die tatsächlich genutzten Operationen
Dokumentation und Roadmap
- Zugehörige Dokumentation und API-Referenzen
- Für den Bau skalierbarer Web-Apps und Server ist eine Architektur nötig, die Hintergrundaufgaben in Queues auslagert, doch herkömmliche Ansätze haben viele Einrichtungsschritte
- Deno Queues ist in die Runtime integriert und läuft auf der Infrastruktur von Deno Deploy, sodass sich mit wenigen Zeilen Code eine serverlose verteilte Queue nutzen lässt
- Deno Queues wird zusammen mit Deno KV, web standards APIs, npm und all-in-one modern tooling als Baustein positioniert, um Webentwicklung einfach und produktiv zu machen
- Feedback und Feature-Requests können über Discord oder die deploy_feedback issues eingereicht werden
1 Kommentare
Meinungen auf Hacker News
Habe gerade das Innenleben der lokalen SQLite-Version untersucht und meine Notizen zusammengefasst: https://til.simonwillison.net/deno/deno-kv#user-content-deno...
Der interessanteste Teil ist vermutlich das Schema, das für diese Funktion verwendet wird:
CREATE TABLE queue ( ts integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (ts, id) );CREATE TABLE queue_running( deadline integer not null, id text not null, data blob not null, backoff_schedule text not null, keys_if_undelivered blob not null, primary key (deadline, id) );CREATE INDEX kv_expiration_ms_idx on kv (expiration_ms);Sind Indizes nicht genau für so etwas gedacht?
Das ist ziemlich neu, aber auch etwas beunruhigend. Natürlich muss kommerzialisiert werden, aber es hätte nicht vollständig geschlossen sein müssen; für die Erweiterungsschicht hätte man wohl auch andere Lizenzen wie BSL oder PolyForm verwenden können.
Ich finde, die Richtung, die Deno hier einschlägt, ist ziemlich zukunftsorientiert
Ich benutze Go dieses Jahr zum ersten Mal, und Teile der Sprache ähneln C sehr. Neben den Unterschieden zu C, etwa dass man dank Garbage Collection Werte zurückgeben kann, die wie auf dem Stack allozierte Pointer aus Funktionen aussehen, sind auch eingebaute Features wie
map[string]stringganz natürlich integriert. Wenn man nach 2023 eine neue Sprache entwickelt, fühlt es sich fast absurd an, keine eingebaute Syntax für Map-Typen zu habenDeshalb wirkt es logisch, dass ein Ökosystem rund um Webserver Bibliotheken für primitive Funktionen bekommt, die wir häufig nutzen – und vielleicht irgendwann sogar Sprachsyntax dafür. Ich kann mich an kein jüngeres Projekt mit verteilten Webservern erinnern, das nicht einmal einen Key-Value-Store für Caches, einen Locking-Mechanismus oder auch nur eine temporäre Queue hatte. Ein verteiltes System ohne Key-Value-Store ähnelt vage einer Programmiersprache ohne Map-Typ und ist wirklich eine Art Schweizer Taschenmesser unter den Technologien
Das potenzielle Problem ist, dass Deno diesen Weg allein geht. Es ist schwer abzuschätzen, ob die neuen Funktionen, die Deno derzeit hinzufügt, auch auf konkurrierenden Plattformen verfügbar sein werden. Und selbst wenn die API als Open Source veröffentlicht wird: Sie liegt im
Deno-Namespace, daher weiß ich nicht, ob es einfach funktioniert, wenn man auf AWS statt FoundationDB lieber Redis verwenden möchteDeshalb habe ich das Gefühl, Deno lieber meiden zu wollen. Die Syntax und die exponierten Funktionen sind wirklich attraktiv, aber ich mache mir Sorgen, dass ich nach einer Abhängigkeit davon den Code umfangreich umbauen müsste, um ihn auf mehreren Cloud-Infrastrukturen deploybar zu machen. Viele Kunden verlangen genau das. Wenn man zum Beispiel irgendwann an Oracle oder Salesforce verkaufen möchte und diese On-Premises-Ausführung verlangen, bleibt es an mir hängen, herauszufinden, wie ich den dort verfügbaren Key-Value-Store an die Funktionalität des
Deno-Pakets anpasseDas ist ein zweischneidiges Schwert. Deno könnte damit Erfolg haben, diese Vision einem breiteren Publikum aufzudrängen, aber vorerst werde ich es wohl vorsichtig betrachten
Ich habe
kv-connect-kit, eine Implementierung dieses Protokolls in reinem TypeScript, kurz ausprobiert; es stellt eine KV-Client-API in jeder JavaScript-Runtime bereit. Das schließt auch Cloudflare Workers ein, wo es keinerlei Deno-Namespace gibtGitHub: https://github.com/skymethod/kv-connect-kit / npm: https://www.npmjs.com/package/kv-connect-kit / deno/x: https://deno.land/x/kv_connect_kit / Demo: https://keyspace.deno.dev/
Das Protokoll scheint wie beschrieben zu funktionieren, und auch andere Backends zu schreiben wirkt ziemlich unkompliziert
Die Tech-Branche hat erhebliche Fortschritte dabei gemacht, sich von Vendor-Lock-in-Stacks zu lösen; das hier erinnert eher wieder an diese Zeiten
Ich sehe keinen praktischen Unterschied zwischen
Deno.KVals Teil der Runtime und einemimport KVam Anfang der Datei. Letzteres kann man von Deno oder von wo auch immer beziehenUnd wie wahrscheinlich ist es, dass das Deno-Team Bindings für andere Sprachen als die eigene bereitstellt? Würde man es zukunftsorientiert nennen, wenn Google anfangen würde, Google-Cloud-spezifische Primitive nativ in Go einzubauen?
Gleichzeitig müsste Self-Hosting genauso gut oder besser sein als bei den Branchenführern. Ein anderer Weg wäre, Self-Hosting aufzugeben und eine Multicloud-Lösung anzubieten, die auf Adaptern zu Hosting-Partnern basiert und eine kleine Marge aufschlägt. Dann müsste Deno nicht direkt als Hosting-Anbieter konkurrieren
Das wirkt für mich weniger zukunftsorientiert als vielmehr wie die Monetarisierung von Deno als SaaS. Es ist das, was heutzutage in der JavaScript-Welt alle mit „Cloud“-Produkten machen: ein Framework drankleben und AWS weiterverkaufen. Deshalb hängt auch ein Preisschild daran
Wenn Denos KV von FoundationDB abhängt, scheint es auch unwahrscheinlich, dass aktiv Adapter für andere Datenbanken gebaut werden. Datenbanktechnologie zu wechseln ist immer eine große Sache, weil jede ihren eigenen Einsatzzweck und ihre eigenen Performance-Eigenschaften hat
GC allowing one to return what look like stack allocated pointers from functionsliegt meiner Meinung nach weniger an der Garbage Collection als vielmehr an Escape Analysis und SSADie Argumentation, dass „man sich durch Boilerplate-Code und komplizierte Konfiguration wühlen muss, um Public-Cloud-Infrastruktur zu nutzen, was viel Zeit und Energie von Entwicklern frisst“, überzeugt mich nicht wirklich.
Am Ende bauen wir Infrastruktur, die stabil sein muss. 30 Minuten dafür aufzuwenden, eine bewährte Technik wie eine SQS-Queue einzurichten, wirkt nicht schlechter, als einer Spielzeug-Queue, die Deno „auf SQLite / FoundationDB“ gebaut hat, vollständig zu vertrauen. Ist der Einrichtungsaufwand von 30 Minuten und die verbesserte „Developer Experience“ dieses Risiko wirklich wert? Wie oft richtet man überhaupt eine Queue ein?
Als Hobbyprogrammierer nutze ich große Anbieter wie AWS oder Google nicht besonders, weil sie ziemlich komplex wirken. Wenn man damit vertraut ist, ist es vielleicht gar nicht so schlimm.
Außerdem möchte ich jedes Projekt als eigenes Repository auf GitHub haben. Idealerweise sollte eine Web-App für jede andere Person einfach unter einer eigenen Domain als unabhängige Web-App startbar sein. Denn ich möchte nicht auch noch für die Daten anderer Leute verantwortlich sein.
Das ähnelt in gewisser Weise dem Sandstorm-Use-Case. Eine Installationsanleitung wie „probier es lokal aus, und wenn du es wirklich nutzen willst, erstelle ein Deno-Deploy-Konto“ klingt ziemlich vernünftig.
Wenn jemand eine gleichwertige Bibliothek für die Cloud anbietet, wird es sicher Leute geben, die sie übernehmen. Im Fall von Deno scheint man gemeinsame Probleme der Entwickler im eigenen Ökosystem zu identifizieren und mit gebündelten, brauchbaren Lösungen anzugehen.
Wenn man eine Workflow-Engine nutzt, die Queues abstrahiert, kann man „einfach Code schreiben“, ohne Jobs, Zeitpläne, Status und Retries selbst zu verwalten.
https://www.inngest.com/blog/how-durable-workflow-engines-wo...
Allerdings bin ich als Autor einer Workflow-Engine voreingenommen.
Aus früherer Erfahrung mit „At-least-once-Delivery-Semantik“ und „User-Code“: Nutzer verstehen At-least-once Delivery nicht richtig.
In dem Moment, in dem eine Nachricht erneut zugestellt wird, hagelt es Nutzerbeschwerden und Ausfälle.
Entweder man vollbringt das beinahe Unmögliche und erfindet Exactly-once-Delivery-Semantik, oder man sollte meiner Meinung nach immer 0,1 % aller Nachrichten erneut zustellen, damit Nutzer sich nicht darauf verlassen können, dass sie nur einmal zugestellt werden.
Ich nutze derzeit Deno Deploy, und für ein Solo-Projekt ist die Performance hervorragend und es ist wirklich einfach.
Aus der Perspektive von jemandem, der in großen Teams AWS-Entwicklung gemacht hat, begrüße ich den Trend, Komplexität loszuwerden und Dinge einfach starten zu können, ohne über Konfiguration nachzudenken. DNS war ebenfalls sehr einfach, und die automatischen SSL-Zertifikate waren wirklich gut. Ich habe überhaupt nichts daran auszusetzen, worauf dieses Produkt abzielt, und freue mich auf die Roadmap.
Wenn ich nichts übersehen habe, sieht es so aus, als gäbe es pro
Deno.openKv()-Instanz nur eine Queue.In der lokalen Version könnte man vermutlich mehrere Queues erstellen, indem man jedes Mal
Deno.openKv("db-2.db")mit einem anderen SQLite-Dateipfad aufruft, aber für eine ziemlich übliche Anforderung wirkt das nach viel Overhead.Vielleicht ist das auch Denos Architekturstil. Erwartet man bei komplexen Apps mit Deno eine Microservice-artige Struktur, bei der mehrere Skripte zusammenarbeiten und jedes seinen eigenen KV-Store und seine eigene Queue hat?
Einer der Kernentwickler hat das auf Discord bestätigt: https://discord.com/channels/684898665143206084/115671428253...
Zitat: „Ja, richtig. Derzeit unterstützen wir nur eine einzelne Queue. Man kann aber mehrere Nachrichtentypen über diese eine Queue multiplexen.“
Wie sieht es mit den Preisen aus?
Ich dachte, Deno sei eine Art Node.js-Alternative; übersehe ich da etwas? Kann man das lokal oder self-hosted kostenlos nutzen?
Da „Queues are built on Deno KV“ gilt: lokal wird SQLite genutzt, und auf Deno Deploy wird FoundationDB für maximale Verfügbarkeit und Durchsatz verwendet.
Zu diesem Muster habe ich hier etwas mehr aufgeschrieben: https://til.simonwillison.net/deno/deno-kv
Falls die Entwickler mitlesen: Bei der derzeit hervorragenden Nutzbarkeit von KV sieht es für mich so aus, als könnte Zugriffskontrolle später schmerzhaft werden.
Ich frage mich, ob die Lösung einfach lautet: „Implementiere es selbst im Userspace und mach keine Bugs“, oder ob dafür etwas geplant ist.
Die jüngste Jupyter-Unterstützung und diese Queue-Funktion machen mich neugierig. Das sind wirklich tolle Dinge.
Aber ich glaube nicht, dass ich einen Server mit Deno schreiben und auf meinem eigenen Server in Produktion betreiben würde. Serverless mag ich nicht.
Die Geschäftsmodelle von Deno und Bun sind um Serverless herum gebaut, also um Deno Deploy. Und Deno Deploy ist wiederum eine andere Runtime.
Bei KV und Queues wird das deutlich. Lokal oder self-hosted bekommt man eine gerade so funktionierende Version, die auf anderer Technologie aufsetzt.
Das bedeutet: Man self-hostet eine andere Version von Deno als die, die die meisten Deno-Kunden verwenden.
Wie viele Leute nutzen Deno, um Server auf eigener Hardware zu betreiben? Wenn diese Zahl klein ist, würde ich lieber Node verwenden.
Deno ist wirklich spannend. Ein tragfähiges Geschäftsmodell, gute Usability und kein unnötiger Konfigurationsaufwand sind großartig
Deno selbst ist im Kern Node.js plus automatische TypeScript-Kompilierung. Früher hätte man dafür nur eine zusätzliche Konfigurationsdatei gebraucht. Als das Projekt herauskam, wurde stark damit geworben, sich vom chaotischen NPM-Ökosystem zu lösen, aber am Ende musste man doch NPM-Unterstützung hinzufügen, und auch dieses Unterscheidungsmerkmal verschwand.
Deno Deploy ist wie die Dutzenden bereits existierenden Lambda-artigen Dienste. Der KV-Store und nun die Queue sind Redis, LevelDB, RocksDB, Dynamo, SQS oder unzähligen ähnlichen Optionen gleichwertig. Ich habe noch keine Funktion gesehen, die Deno wirklich vom Rest abhebt.
Wenn man es bevorzugt, dass ein Unternehmen Sprachruntime, Compute-Hosting und Datenspeicher komplett übernimmt, kann das attraktiv sein. Ich persönlich würde das aber lieber vermeiden, besonders wenn dieses Unternehmen in dem Bereich keine Erfolgsbilanz vorzuweisen hat.