Warum ein langsamer Aufruf zum Auftrag wird
Eine Auftragswarteschlange lässt eine Anfrage sofort antworten, während die langsame Arbeit woanders fertig wird. Ein Modellaufruf kann viele Sekunden dauern, und eine Webanfrage, die so lange wartet, läuft in ein Zeitlimit oder blockiert einen Prozess. Das ist wichtig, weil bei der Wiederholung eines langsamen Aufrufs ein Kunde doppelt belastet wird.
Eine Nutzerin schickt vierzig Seiten zum Zusammenfassen. Der Server antwortet in wenigen Millisekunden „angenommen, auftrag-17“. Die Seite fragt den Status ab, bis die Zusammenfassung fertig ist.
Am Ende dieser Lektion
Notiz
Ich kann einen langsamen Aufruf aus der Anfrage herausnehmen und seinen Fortschritt melden.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Auftrag | eine Einheit langsamer Arbeit mit einem Zustand | |
| Warteschlange | die Aufträge, die auf einen Arbeiter warten | |
| Arbeiter | Code, der einen Auftrag nimmt und ausführt | |
| Idempotenzschlüssel | eine Kennung des Kunden, die eine Wiederholung harmlos macht | bestellung-1 |
| Backoff | nach jedem Fehlschlag länger warten |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Auftrag hat vier Zustände
Ein Auftrag ist wartend, dann laufend, dann fertig oder gescheitert. Ein fehlgeschlagener Versuch, der wiederholt wird, geht zurück auf wartend. Der Auftrag behält seine Versuchszahl und sein Ergebnis.
Der Kunde bekommt sofort eine Auftrags-ID. Er fragt den Status mit dieser ID ab. Er liest das Ergebnis erst, wenn der Zustand fertig ist.
Beispiel: auftrag-2 scheitert einmal
| Schritt | Zustand | Versuche | Uhr |
|---|---|---|---|
| Eingereicht | wartend | 0 | 0 s |
| Erster Versuch beginnt | laufend | 1 | 2 s |
| Zeitüberschreitung beim Anbieter | wartend | 1 | 7 s |
| Zweiter Versuch beginnt | laufend | 2 | 9 s |
| Ergebnis abgelegt | fertig | 2 | 9 s |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Idempotenzschlüssel verhindert doppelte Ausführung
Netze wiederholen Anfragen. Ein Kunde kann zweimal auf Senden drücken, oder ein Proxy sendet erneut. Ohne Schutz wird jede Kopie zu einem Auftrag, und die Arbeit und die Rechnung verdoppeln sich.
Der Kunde sendet einen Idempotenzschlüssel. Die Warteschlange führt eine Tabelle von Schlüssel zu Auftrags-ID. Ein schon bekannter Schlüssel liefert den vorhandenen Auftrag und erzeugt keinen neuen.
Wiederholungen sind begrenzt und gestaffelt
Legen Sie eine Höchstzahl an Versuchen fest. Danach ist der Auftrag gescheitert, und ein Mensch oder eine Regel entscheidet weiter. Warten Sie nach jedem Fehlschlag länger, damit ein angeschlagener Dienst Luft hat.
Ein fertiger Auftrag wird nie wieder ausgeführt, auch wenn ein Durchlauf ihn zweimal besucht. Ein fertiger Auftrag ist ein Ergebnis, keine Anforderung.
Ein häufiger Fehler
Warnung
Viele glauben, eine Wiederholung sei immer sicher. Sie ist es nur, wenn die Arbeit idempotent ist oder die Warteschlange sie kennt. Wiederholen Sie einen bereits bezahlten und beendeten Aufruf, zahlen Sie erneut. Prüfen Sie den Zustand vor jeder Ausführung.
Das Modell-Hilfsskript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' 'async function fragen(nachrichten, probe, max) {' ' try {' ' const res = await fetch(basis + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' return (await res.json()).choices[0].message.content;' > model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Modell-Hilfsskript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' const liste = [].concat(probe);' ' const runde = nachrichten.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return liste[Math.min(runde, liste.length - 1)];' ' }' '}' 'module.exports = { fragen };' >> model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Warteschlange schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' 'const auftraege = {}; // Auftrags-ID auf Auftrag' 'const nachSchluessel = {}; // Idempotenzschlüssel auf Auftrags-ID' 'let uhr = 0; // eine falsche Uhr, in Sekunden' 'let naechster = 1;' 'function einreichen(schluessel, nutzlast) {' ' if (schluessel in nachSchluessel) return nachSchluessel[schluessel];' ' const id = \"auftrag-\" + naechster++;' ' auftraege[id] = { id: id, nutzlast: nutzlast, zustand: \"wartend\", versuche: 0, ergebnis: null };' ' nachSchluessel[schluessel] = id;' ' return id;' '}' > queue.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Warteschlange schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const ausfallErst = { \"auftrag-2\": 1 }; // auftrag-2 scheitert einmal, dann klappt es' 'function arbeiten(auftrag) {' ' if (auftrag.versuche <= (ausfallErst[auftrag.id] || 0)) throw new Error(\"Zeitüberschreitung beim Anbieter\");' ' return auftrag.nutzlast.toUpperCase();' '}' 'function ausfuehren(auftrag) {' ' if (auftrag.zustand === \"fertig\" || auftrag.zustand === \"gescheitert\") return;' ' while (auftrag.versuche < 3) {' ' auftrag.versuche++;' ' auftrag.zustand = \"laeuft\";' ' uhr += 2;' ' try { auftrag.ergebnis = arbeiten(auftrag); auftrag.zustand = \"fertig\"; return; }' ' catch (fehler) { auftrag.zustand = \"wartend\"; uhr += auftrag.versuche * 5; }' ' }' ' auftrag.zustand = \"gescheitert\";' '}' >> queue.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Warteschlange schreiben, Teil 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'einreichen(\"bestellung-1\", \"rechnung a\");' 'einreichen(\"bestellung-2\", \"rechnung b\");' 'einreichen(\"bestellung-1\", \"rechnung a\"); // der Kunde versucht es erneut: gleicher Schlüssel, gleicher Auftrag' 'Object.values(auftraege).forEach(ausfuehren);' 'Object.values(auftraege).forEach(ausfuehren); // ein zweiter Durchlauf führt nichts aus' 'for (const id in auftraege) console.log(id, auftraege[id].zustand, \"Versuche\", auftraege[id].versuche, auftraege[id].ergebnis);' 'console.log(\"Aufträge:\", Object.keys(auftraege).length, \"Uhr:\", uhr + \" s\");' >> queue.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Warteschlange schreiben, Teil 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const probe = \"Ihre beiden Rechnungen sind fertig.\";' ' const text = \"Zwei Aufträge sind fertig. Schreiben Sie eine kurze Statuszeile für den Kunden.\";' ' console.log(\"Echter Aufruf:\", await fragen([{ role: \"user\", content: text }], probe, 40));' '}' 'main();' >> queue.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Warteschlange ausführen
docker exec -w /home/node/project agent node queue.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein Stellvertreter, keine echte Warteschlange
Die Warteschlange hier ist ein Objekt im Speicher und die Uhr eine Zahl. Hält der Prozess an, sind alle Aufträge verloren. Ein echtes System legt Aufträge in einem dafür gebauten Dienst ab, und Arbeiter laufen in anderen Prozessen.
Die Ideen bleiben gültig: Zustände, eine Versuchszahl, eine Schlüsseltabelle und eine Grenze für Wiederholungen.
Eine mögliche Ausgabe
| Zeile | Was sie zeigt |
|---|---|
| auftrag-1 fertig Versuche 1 RECHNUNG A | Ein Auftrag, der beim ersten Mal klappte |
| auftrag-2 fertig Versuche 2 RECHNUNG B | Ein Auftrag, der einmal scheiterte und dann klappte |
| Aufträge: 2 Uhr: 11 s | Drei Einreichungen ergaben zwei Aufträge |
| Echter Aufruf | Eine kurze Statuszeile oder eine gekennzeichnete aufgezeichnete Probe |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.