Start / Seminare / FastAPI Architektur in der Praxis

Modul

Nebenläufigkeit härten

7 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Nebenläufigkeit härten

0:00 Bis hierhin hat unsere Anwendung immer eine Sache nach der anderen gemacht. Das letzte Modul bricht damit. Wir lassen vier Aufgaben gleichzeitig laufen, streamen den Fortschritt live an einen Bildschirm in der Disposition, und am Ende stellen wir eine Frage, die viele Anwendungen erst im Betrieb stellen: Was passiert eigentlich mit geteiltem Zustand, wenn mehrere Prozesse laufen?

0:20 Auf dem Weg dorthin lernen wir das Fehlerbild kennen, bei dem eine einzige Funktion den kompletten Server einfriert — und warum asynchrone Syntax davor nicht schützt.

Muster für Echtzeit und Nebenläufigkeit

0:30 Bevor Code entsteht, sortieren wir das Feld. Zwei Entscheidungen stehen an. Die erste: Wie starten wir mehrere Aufgaben gleichzeitig, und was soll passieren, wenn eine davon scheitert? Die zweite: Wie kommt ein Fortschritt zum Zuschauer, ohne dass der dauernd nachfragen muss? Für beide gibt es mehrere Antworten, und die Wahl hängt weniger von der Technik ab als von der Anforderung.

0:53 Schauen wir uns an, was bei einer Freigabe tatsächlich zu tun ist. Die Prüfplaketten der Geräte müssen kontrolliert werden — bei Veranstaltungstechnik ist das keine Formalie, sondern Vorschrift. Das Ausfallrisiko wird bewertet. Eine Rechnung entsteht. Und die Disposition bekommt Bescheid. Vier Aufgaben, und keine braucht das Ergebnis einer anderen. Nacheinander ausgeführt verschenken sie schlicht Zeit.

1:17 Es ist wie an einer Supermarktkasse mit vier freien Kassen, an denen sich alle in einer Schlange anstellen — das Ergebnis stimmt, nur dauert es viermal so lange. Achten Sie auf die Spalte in der Mitte: Drei der vier Aufgaben warten, eine rechnet. Das klingt nach einem Detail und ist der wichtigste Unterschied in diesem ganzen Modul.

1:37 Warten kann man beliebig oft gleichzeitig — der Prozessor hat dabei ja nichts zu tun. Rechnen nicht. Die zweite Zeile ist deshalb die einzige, die eine Sonderbehandlung braucht, und im dritten Kapitel sehen Sie, was passiert, wenn man sie ihr nicht gibt. Die Fußnote nennt den Ertrag: So lange wie die langsamste Aufgabe, nicht so lange wie alle zusammen.

1:58 Die Entscheidung fällt hier ungewöhnlich leicht, wenn man die Anforderung ernst nimmt. Der Dispo-Monitor ist ein Bildschirm an der Wand. Er zeigt an, er fragt nichts. Ein Zweiwegkanal wäre also eine Fähigkeit, die niemand nutzt — und die trotzdem bezahlt werden will, mit einem eigenen Protokoll, eigener Lebenszykluspflege und eigener Skalierungsgeschichte.

2:20 Server-Sent Events laufen dagegen über ganz normales HTTP. Alles, was Sie über Proxys, Caching und Lastverteilung wissen, gilt weiter. Das ist ein guter Handel, solange die Richtung wirklich einseitig bleibt. Der erste Punkt räumt mit einem verbreiteten Missverständnis auf: Nebenläufig ist nicht parallel. Der Event Loop bleibt ein einziger Thread, und in jedem Augenblick läuft genau eine Sache. Der Gewinn entsteht nur dadurch, dass wartende Aufgaben sich abwechseln.

2:48 Daraus folgt der zweite Punkt: Vier Aufgaben gleichzeitig zu starten hilft, wenn sie warten, und hilft überhaupt nicht, wenn sie rechnen. Vier rechenintensive Aufgaben nebenläufig zu starten macht die Sache sogar unübersichtlicher, ohne eine Sekunde zu sparen. Behalten Sie das im Kopf, wir kommen im dritten Kapitel darauf zurück.

Freigabe mit TaskGroup und Executor

3:08 Jetzt wird es konkret. Wir bauen die Freigabe von einer Zeile Platzhalter zu einem echten Ablauf aus. Zwei Werkzeuge kommen dabei zum Einsatz: eines, das die vier Aufgaben zusammenhält und dafür sorgt, dass ein Fehlschlag keine halben Ergebnisse hinterlässt. Und eines, das die rechenintensive Aufgabe vom Event Loop wegnimmt, bevor sie dort Schaden anrichtet.

3:29 Beide sind wenige Zeilen Code — der Gewinn steckt nicht im Umfang, sondern in den Zusagen, die sie geben. Die Aufgabengruppe hat zwei Zusagen, und beide sind wertvoll. Die erste: Der Block wird nicht verlassen, bevor alle Aufgaben fertig sind. Sie können sich also darauf verlassen, dass hinter dem Block wirklich alles erledigt ist. Die zweite ist die wichtigere: Scheitert eine Aufgabe, werden die übrigen abgebrochen.

3:56 Denken Sie an eine Reisebuchung — wenn der Flug nicht klappt, wollen Sie auch das Hotel nicht. Für unsere Freigabe heißt das: Ein Angebot, das die Plakettenprüfung nicht besteht, darf keine Rechnung auslösen. Nicht eine halbe, gar keine. Worauf es hier ankommt, sind zwei Dinge. Erstens: Bei zwei der vier Aufgaben merken wir uns das Ergebnis, bei den anderen beiden nicht — wir brauchen ja nur die Rechnungsnummer und den Risikowert.

4:22 Zweitens, und das ist der eigentliche Gewinn: Die Zeile hinter dem Block. Wenn die Ausführung dort ankommt, ist garantiert alles gut gegangen. Es braucht keine Prüfung, ob vielleicht doch eine Aufgabe fehlgeschlagen ist. Entweder Sie stehen hinter dem Block, dann hat alles geklappt, oder Sie stehen im Fehlerzweig. Diese Klarheit ist der Grund, warum sich das Werkzeug lohnt.

4:45 Diese vier Zeilen sind die Sonderbehandlung für die rechnende Aufgabe. Statt die schwere Funktion direkt aufzurufen, wird sie an einen Threadpool übergeben. Der Aufruf sieht von außen aus wie jedes andere Warten — und genau das ist der Trick. Für den Event Loop ist die Aufgabe jetzt eine wartende, und er kann sich in der Zwischenzeit um andere Anfragen kümmern. Die eigentliche Rechnerei passiert in einem anderen Thread.

5:09 Wichtig ist die Fußnote: Dieser Pool ist gemeinsam und klein. Er eignet sich für kurze Spitzen, nicht für Dauerlast. Hier steckt eine Falle drin, die man nur einmal erlebt und dann nie vergisst. Wenn eine Aufgabe in der Gruppe scheitert, kommen die Fehler gebündelt heraus — mehrere Aufgaben können ja gleichzeitig scheitern.

5:29 Es gibt dafür eine eigene Syntax zum Herausgreifen. Und jetzt der Punkt: Werfen Sie innerhalb dieses Blocks einen HTTP-Fehler, wird der wieder eingepackt und erreicht FastAPI nie. Der Aufrufer sieht einen internen Serverfehler statt einer sauberen Konfliktmeldung. Die Lösung ist unspektakulär — im Block nur ein Kennzeichen setzen und danach werfen.

5:50 Zwei Nachweise gehören zu dieser Aufgabe. Der erste ist der angenehme: Messen Sie die Dauer. Vier Aufgaben müssen zusammen etwa so lange brauchen wie die langsamste, nicht so lange wie alle addiert. Der zweite ist der wichtigere: Markieren Sie ein Angebot so, dass die Plakettenprüfung scheitert, und schauen Sie nach, ob wirklich keine Rechnung entstanden ist und keine Benachrichtigung hinausging.

6:12 Genau das ist die Zusage der Aufgabengruppe, und genau das unterscheidet sie von einem einfachen Parallelstart.

Event Loop und strukturierte Nebenläufigkeit

6:19 Wir haben zwei Werkzeuge benutzt und dabei zwei Fragen offengelassen. Warum genau fror eine einzige Funktion den ganzen Server ein? Und was genau sagt uns die Aufgabengruppe eigentlich zu? Beide Antworten liegen eine Ebene tiefer, in der Maschinerie darunter. Es lohnt sich, dort einmal hinzuschauen — nicht aus Neugier, sondern weil man danach eine ganze Klasse von Fehlern erkennt, bevor sie entsteht.

6:42 Und weil sich diese Fehler sonst hartnäckig als Performance-Probleme tarnen. Der Event Loop ist im Kern ein einzelner Thread mit einem Terminplaner. Er führt immer genau eine Koroutine aus. Der Wechsel passiert an einer einzigen Sorte von Stellen: dort, wo im Code gewartet wird. Genau dort gibt eine Koroutine die Kontrolle zurück, und der Planer sucht sich die nächste, die dran ist. Denken Sie an einen Kellner, der viele Tische bedient.

7:09 Solange er zwischendurch immer wieder zurücktritt, wirkt es, als wäre er überall gleichzeitig. Setzt er sich aber an einen Tisch und bleibt, warten alle anderen. Damit ist der Fall aufgeklärt. Unsere Risikobewertung lief über Millionen von Schleifendurchläufen, und in keinem einzigen davon wurde gewartet. Der Kellner hat sich hingesetzt.

7:30 Der Planer kam während dieser ganzen Zeit zu niemandem sonst — auch nicht zu dem Endpunkt, der eigentlich nur melden soll, dass der Dienst noch lebt. Das ist der wichtige Teil: Der Ausfall betrifft nicht die eine Anfrage, sondern alle. Und noch etwas: Die Funktion asynchron zu deklarieren ändert daran gar nichts. Es geht nicht um das Schlüsselwort, sondern darum, ob tatsächlich gewartet wird.

7:53 Die Tabelle beantwortet die Frage nach der Zusage. Der erste Weg ist der gefährlichste, gerade weil er der einfachste aussieht: Die Aufgabe läuft los, und niemand hält sie fest. Scheitert sie, merkt es unter Umständen niemand — der Fehler taucht irgendwann beim Aufräumen im Protokoll auf, weit weg vom Geschehen. Der zweite Weg sammelt die Ergebnisse ein, lässt aber die Geschwister weiterlaufen, wenn eine scheitert. Für unsere Freigabe wäre das falsch.

8:20 Deshalb der dritte Weg — er ist der einzige, der unsere fachliche Regel abbildet. Die ersten beiden Punkte gehören zusammen und sind eine wichtige Abgrenzung. Der Threadpool aus dem zweiten Kapitel ist keine Auftragswarteschlange. Er hat wenige Arbeiter, und alle Aufrufe im Prozess bedienen sich daraus. Eine kurze Rechenspitze — unsere Risikobewertung — passt dort hinein.

8:43 Ein Auftrag, der Minuten läuft, blockiert dagegen einen der wenigen Plätze und nimmt ihn allen anderen weg. Für solche Arbeiten gibt es eigene Systeme, die außerhalb Ihres Webprozesses laufen. Die Faustregel: Wenn Sie über einen Fortschrittsbalken nachdenken, gehört es nicht mehr in den Executor.

Fortschritt streamen mit SSE

9:01 Die Freigabe läuft jetzt nebenläufig. Aber wer sie ausgelöst hat, sieht bis zum Ende nichts. Bei einem Vorgang, der mehrere Sekunden dauert, ist das unbefriedigend. Das ändern wir: Die Disposition bekommt einen Bildschirm, auf dem die Stände durchlaufen. Technisch ist das erstaunlich wenig Code — und enthält trotzdem eine Falle, die direkt an das anknüpft, was wir über die Lebensdauer von Dependencies gelernt haben.

9:27 Das Protokoll ist so einfach, dass man es kaum glauben mag: Textzeilen über eine offen gehaltene HTTP-Verbindung. Ein Ereignis besteht aus einer Zeile mit den Daten und einer Leerzeile dahinter. Mehr nicht. Kein Handshake, kein Rahmenformat, keine Bibliothek. Sie können einen solchen Strom mit einem Kommandozeilenwerkzeug mitlesen, und im Browser gibt es dafür ein eingebautes Objekt, das wenige Zeilen JavaScript braucht.

9:52 Diese Schlichtheit ist der eigentliche Grund, warum sich Server-Sent Events für den Fall lohnen — nicht irgendeine Leistungsfähigkeit. Worauf es hier ankommt, ist die Reihenfolge im oberen Teil. Die Session wird geöffnet, es wird gelesen, was gebraucht wird, und dann wird sie geschlossen — bevor die eigentliche Schleife überhaupt beginnt.

10:12 Der Rest des Generators läuft ohne Datenbankverbindung. Das ist kein Stilmittel, sondern Notwendigkeit, und die Begründung steht auf der nächsten Folie. Der untere Teil ist dann fast langweilig: Ein Ereignis bauen, in JSON verwandeln, hinausschreiben, kurz warten. Beachten Sie, dass wir dasselbe Pydantic-Modell benutzen wie überall — der Strom spricht denselben Vertrag wie der Rest der Schnittstelle.

10:36 Hier zahlt sich der Stolperstein aus dem vierten Modul aus. Eine Dependency mit Abbau räumt auf, sobald die Antwort erzeugt ist. Bei einem Strom ist die Antwort aber erzeugt, bevor auch nur ein einziges Ereignis geflossen ist — der Generator läuft ja erst danach. Die injizierte Session wäre also längst geschlossen, wenn der Generator sie brauchte.

10:56 Das ist ein hübsches Beispiel dafür, wie sich ein Detail der Lebensdauer zwei Module später in einem ganz anderen Zusammenhang meldet. Wer den Abbau verstanden hat, sieht diese Falle kommen. Der erste Punkt ist die Rechnung, die man aufmachen sollte, bevor man Ströme einsetzt. Jede offene Verbindung ist eine langlebige Anfrage.

11:15 Tausend Bildschirme in tausend Büros heißen tausend Verbindungen, die dauerhaft offen stehen. Deshalb ist die kurzlebige Session aus dem Code nicht nur technisch nötig, sondern auch wirtschaftlich: Sonst hinge an jeder dieser Verbindungen noch eine Datenbankverbindung. Der letzte Punkt ist eine Begrenzung, die viele überrascht — über die ältere HTTP-Version erlaubt ein Browser nur eine Handvoll Verbindungen je Domain, und jeder Strom belegt eine davon dauerhaft.

SSE im Betrieb

11:42 Auf dem eigenen Rechner funktioniert unser Strom. Zwischen Ihrem Generator und einem Browser im echten Netz liegen aber Proxys, Load Balancer und Zeitüberschreitungen — und die haben mit langlebigen Verbindungen ihre eigenen Gewohnheiten. Meist unangenehme. In diesem Kapitel entsteht deshalb kein neuer Code, sondern es geht um das Wissen, das Sie brauchen, wenn die Sache ausgeliefert wird.

12:04 Alles davon ist entweder Teil des Standards oder ganz normales HTTP-Verhalten. Wir haben bisher nur eines der Protokollfelder benutzt. Es gibt drei weitere, und sie sind der Grund für die beste Eigenschaft des Protokolls. Eines benennt den Ereignistyp, sodass ein Bildschirm Freigaben und Fehler auseinanderhalten kann. Eines vergibt eine laufende Nummer.

12:25 Und eines sagt dem Client, wie lange er nach einem Abbruch warten soll, bevor er es erneut versucht. Alle drei sind schlichte Textzeilen vor der Leerzeile — es kostet Sie nichts, sie mitzuschicken, und es macht aus einem Spielzeug einen betriebsfähigen Strom. Die entscheidende Zeile ist die mit der laufenden Nummer, und die Fußnote erklärt, warum.

12:45 Bricht die Verbindung ab, verbindet der Browser von selbst neu — dafür müssen Sie nichts programmieren. Und er schickt dabei mit, welche Nummer er zuletzt gesehen hat. Damit haben Sie alles, was Sie brauchen, um genau dort weiterzumachen. Das Protokoll liefert also den Haken, die Erinnerung müssen Sie liefern. Ohne diese Erinnerung fängt Ihr Dispo-Monitor nach jedem kurzen Netzwerkhänger wieder beim ersten Stand an, und niemand weiß, ob das ein neuer Vorgang ist.

13:12 Fünf Schritte, und sie zerfallen in zwei Gruppen. Die ersten beiden betreffen Ihren Code: Nummern vergeben und beim Wiederverbinden auswerten. Die übrigen drei betreffen die Infrastruktur und sind reine Konfiguration. Der dritte Schritt ist der, der am häufigsten vergessen wird — Reverse Proxys puffern Antworten von Haus aus, und Pufferung ist Gift für einen Strom.

13:33 Die Ereignisse sammeln sich dann im Proxy und kommen als ein später Schwall an. Funktional korrekt, und der Live-Eindruck ist trotzdem dahin. Der zweite Punkt betrifft eine Eigenheit von Netzwerkkomponenten, mit der man rechnen muss. Eine Verbindung, über die nichts fließt, sieht für einen Load Balancer tot aus — und wird nach einer Weile gekappt.

13:54 Unser Demonstrationsstrom merkt davon nichts, weil er im Sekundentakt sendet. Ein echter Freigabefortschritt kann aber minutenlang stillstehen, während eine Prüfung läuft. Deshalb schickt man regelmäßig eine Kommentarzeile — der Client ignoriert sie, die Verbindung bleibt warm. Ein Lebenszeichen, das nichts bedeutet und alles rettet.

Middleware und Thread-Sicherheit

14:15 Zwei Punkte fehlen noch, und sie haben auf den ersten Blick wenig miteinander zu tun. Der eine: Wie meldet die Anwendung eigentlich Fehler, wenn etwas wirklich schiefgeht — und wie findet man die zugehörige Spur im Protokoll wieder? Der andere: Was passiert mit Daten, die sich mehrere Threads teilen? Beide behandeln wir in diesem Kapitel, und beim zweiten wird es interessanter, als es zunächst klingt — er führt uns direkt zum Abschluss des Seminars.

14:41 Middleware ist eine Funktion, die sich um jede einzelne Anfrage legt — davor und danach. Sie ist damit der ideale Ort für alles, was für sämtliche Endpunkte gleich gelten soll. In unserem Fall zwei Dinge: eine Kennung, die jede Anfrage bekommt und die im Protokoll wieder auftaucht, und ein einheitlicher Umschlag für Fehler, die niemand behandelt hat.

15:00 Denken Sie an den Poststempel: Er wird nicht vom Absender aufgebracht und nicht vom Empfänger, sondern von einer Stelle dazwischen, die jeden Brief sieht. Zwei Dinge passieren hier, und beide zahlen auf dieselbe Sache ein. Die Kennung wird entweder übernommen, wenn der Aufrufer schon eine mitbringt, oder neu erzeugt. Und wenn etwas durchschlägt, was niemand behandelt hat, wird es protokolliert — mit dieser Kennung — und der Aufrufer bekommt einen aufgeräumten Fehler statt eines Stacktrace.

15:29 Worauf es ankommt: Dieselbe Kennung steht danach im Antwortkopf. Ruft jemand an und nennt sie, finden Sie die zugehörigen Protokollzeilen sofort. Das ist eine der billigsten Maßnahmen mit dem größten Effekt im Betrieb. Denken wir das einmal in Zeitlupe durch. Hochzählen sieht aus wie ein Schritt und sind in Wahrheit drei: lesen, eins dazu, schreiben.

15:50 Wenn zwei Threads wirklich gleichzeitig laufen, kann der zweite den Wert lesen, bevor der erste seinen geschrieben hat. Beide rechnen dann mit demselben Ausgangswert, beide schreiben dasselbe Ergebnis — und ein Hochzählen ist spurlos verschwunden. Kein Fehler, keine Meldung, nur eine Zahl, die zu klein ist. Ein Lock macht aus den drei Schritten wieder einen unteilbaren, indem er die Threads in eine Reihe zwingt.

16:14 Der erste Punkt ist frisch und wichtig für die Einordnung. Das freie Threading ohne den globalen Interpreter-Lock war in Python 3.13 noch ausdrücklich experimentell. Seit 3.14 ist es offiziell unterstützt — der experimentelle Status ist gefallen. Der Bau bleibt optional, und einthreadiger Code zahlt dort noch einen Aufschlag, aber die Richtung ist klar.

16:37 Was das für Sie heißt, steht im dritten Punkt: Geteilter, veränderlicher Zustand ist die rote Zone. Modulvariablen, Klassenattribute, jeder Cache. Was heute nur selten schiefgeht, geht dort zuverlässig schief.

Zustand über Prozessgrenzen hinaus

16:51 Der Lock hat das Loch innerhalb eines Prozesses geschlossen. Jetzt kommt die Frage, die den Bogen dieses Seminars schließt: Was ist eigentlich, wenn es mehr als einen Prozess gibt? Und das ist keine Randbedingung — es ist die Normalform jedes ernsthaften Betriebs. Sie werden sehen, dass unser schöner Lock damit nicht falsch wird, sondern schlicht unzuständig.

17:12 Ein produktiver Server läuft mit mehreren Arbeitsprozessen, damit er mehrere Prozessorkerne nutzen kann. Und jetzt kommt der Punkt: Getrennte Prozesse heißt getrennter Speicher. Jeder Arbeiter bekommt seine eigene Kopie des Moduls, des Dictionarys und, ja, auch des Locks. Eine Anfrage landet bei Arbeiter eins und zählt dort hoch.

17:32 Die nächste landet bei Arbeiter drei und zählt woanders hoch. Vier Arbeiter, vier Zähler, vier verschiedene Zahlen — und keine davon stimmt. Es ist wie vier Kassen, die jede für sich zählen und am Abend nicht zusammengelegt werden. Diese Unterscheidung ist wichtig, weil sie einen Reflex verhindert. Der Lock ist nicht kaputt und auch nicht falsch eingesetzt — er tut genau das, wofür er gebaut ist.

17:57 Er synchronisiert Threads. Prozesse sind nicht sein Zuständigkeitsbereich, und kein anderer Lock in Ihrem Prozess wäre es. Daraus folgt eine Regel, die man sich merken sollte: Zustand, der geteilt und verändert werden muss, gehört aus dem Prozessspeicher heraus. Nicht besser abgesichert — heraus. Das ist keine Optimierung, sondern eine Frage der Zuständigkeit.

18:19 Die oberste Zeile ist die Ausnahme, und sie zeigt, dass die Regel keine Pauschale ist. Ein Verbindungspool gehört in den Prozess — er verwaltet ja gerade Ressourcen dieses Prozesses. Alles darunter nicht. Und die Fußnote nennt den eleganten Teil der Lösung: Ein externer Speicher wie Redis zählt mit einem einzigen unteilbaren Befehl hoch.

18:39 Es gibt dort gar kein Fenster zwischen Lesen und Schreiben, in das sich jemand hineinschieben könnte. Das Problem verschwindet also nicht, weil wir es besser absichern, sondern weil es an diesem Ort nicht existiert. Der zweite Punkt beschreibt, warum dieser Fehler so gut überlebt. Ein Zähler im Modul verhält sich auf Ihrem Entwicklungsrechner völlig korrekt — dort läuft ja ein Prozess.

19:02 Er verhält sich auch in den Tests korrekt. Er wird erst falsch, wenn jemand die Anwendung mit mehreren Arbeitern startet, und das passiert typischerweise beim Ausrollen, nicht beim Entwickeln. Der letzte Punkt ist Ihre Prüfliste dafür: Modulvariablen, Klassenattribute, jeder Cache, den mehr als ein Thread berührt. Gehen Sie die einmal durch, bevor Sie skalieren.

19:24 Der Nachweis für diese Aufgabe ist besonders befriedigend, weil man ihn sehen kann. Starten Sie die Anwendung mit vier Arbeitsprozessen und rufen Sie den Zähler mehrfach ab. Vorher bekommen Sie vier verschiedene Zahlen, je nachdem, welcher Arbeiter gerade antwortet — die Zahl springt sogar hin und her. Nachher ist es eine, und sie stimmt.

19:43 Damit haben Sie den Unterschied zwischen prozesslokalem und geteiltem Zustand nicht nur gehört, sondern gemessen. Und Sie haben ein Werkzeug an der Hand, um in Ihren eigenen Anwendungen danach zu suchen.

Was die Dispo geworden ist

19:55 Schauen wir zurück, was aus dem Prototyp vom ersten Modul geworden ist. Die Verträge sind Pydantic-Modelle, an jeder Tür geprüft, nicht nur am HTTP-Endpunkt. Die Persistenz ist asynchron, typisiert und mit bewusst gewählter Ladestrategie. Die Verdrahtung ist ein Graph aus Sessions, Services und Wächtern, der sich an jeder Stelle auseinandernehmen und testen lässt.

20:17 Und die Nebenläufigkeit ist strukturiert — alles oder nichts, Rechenarbeit beiseite, Fortschritt live. Nichts davon war exotisch. Es sind die Muster, die einen Prototyp von einem Dienst unterscheiden, den man im Betrieb verteidigen kann.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →