From c457f320d911426ddce9475c95bfbdf76af2ac6c Mon Sep 17 00:00:00 2001 From: Nils Lindemann Date: Sat, 30 Mar 2024 21:30:59 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=90=20Add=20German=20translation=20for?= =?UTF-8?q?=20`docs/de/docs/advanced/events.md`=20(#10693)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/docs/advanced/events.md | 162 ++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 docs/de/docs/advanced/events.md diff --git a/docs/de/docs/advanced/events.md b/docs/de/docs/advanced/events.md new file mode 100644 index 000000000..e29f61ab9 --- /dev/null +++ b/docs/de/docs/advanced/events.md @@ -0,0 +1,162 @@ +# Lifespan-Events + +Sie können Logik (Code) definieren, die ausgeführt werden soll, bevor die Anwendung **hochfährt**. Dies bedeutet, dass dieser Code **einmal** ausgeführt wird, **bevor** die Anwendung **beginnt, Requests entgegenzunehmen**. + +Auf die gleiche Weise können Sie Logik (Code) definieren, die ausgeführt werden soll, wenn die Anwendung **heruntergefahren** wird. In diesem Fall wird dieser Code **einmal** ausgeführt, **nachdem** möglicherweise **viele Requests** bearbeitet wurden. + +Da dieser Code ausgeführt wird, bevor die Anwendung **beginnt**, Requests entgegenzunehmen, und unmittelbar, nachdem sie die Bearbeitung von Requests **abgeschlossen hat**, deckt er die gesamte **Lebensdauer – „Lifespan“** – der Anwendung ab (das Wort „Lifespan“ wird gleich wichtig sein 😉). + +Dies kann sehr nützlich sein, um **Ressourcen** einzurichten, die Sie in der gesamten Anwendung verwenden wollen und die von Requests **gemeinsam genutzt** werden und/oder die Sie anschließend **aufräumen** müssen. Zum Beispiel ein Pool von Datenbankverbindungen oder das Laden eines gemeinsam genutzten Modells für maschinelles Lernen. + +## Anwendungsfall + +Beginnen wir mit einem Beispiel-**Anwendungsfall** und schauen uns dann an, wie wir ihn mit dieser Methode implementieren können. + +Stellen wir uns vor, Sie verfügen über einige **Modelle für maschinelles Lernen**, die Sie zur Bearbeitung von Requests verwenden möchten. 🤖 + +Die gleichen Modelle werden von den Requests gemeinsam genutzt, es handelt sich also nicht um ein Modell pro Request, pro Benutzer, oder ähnliches. + +Stellen wir uns vor, dass das Laden des Modells **eine ganze Weile dauern** kann, da viele **Daten von der Festplatte** gelesen werden müssen. Sie möchten das also nicht für jeden Request tun. + +Sie könnten das auf der obersten Ebene des Moduls/der Datei machen, aber das würde auch bedeuten, dass **das Modell geladen wird**, selbst wenn Sie nur einen einfachen automatisierten Test ausführen, dann wäre dieser Test **langsam**, weil er warten müsste, bis das Modell geladen ist, bevor er einen davon unabhängigen Teil des Codes ausführen könnte. + +Das wollen wir besser machen: Laden wir das Modell, bevor die Requests bearbeitet werden, aber unmittelbar bevor die Anwendung beginnt, Requests zu empfangen, und nicht, während der Code geladen wird. + +## Lifespan + +Sie können diese Logik beim *Hochfahren* und *Herunterfahren* mithilfe des `lifespan`-Parameters der `FastAPI`-App und eines „Kontextmanagers“ definieren (ich zeige Ihnen gleich, was das ist). + +Beginnen wir mit einem Beispiel und sehen es uns dann im Detail an. + +Wir erstellen eine asynchrone Funktion `lifespan()` mit `yield` wie folgt: + +```Python hl_lines="16 19" +{!../../../docs_src/events/tutorial003.py!} +``` + +Hier simulieren wir das langsame *Hochfahren*, das Laden des Modells, indem wir die (Fake-)Modellfunktion vor dem `yield` in das Dictionary mit Modellen für maschinelles Lernen einfügen. Dieser Code wird ausgeführt, **bevor** die Anwendung **beginnt, Requests entgegenzunehmen**, während des *Hochfahrens*. + +Und dann, direkt nach dem `yield`, entladen wir das Modell. Dieser Code wird unmittelbar vor dem *Herunterfahren* ausgeführt, **nachdem** die Anwendung **die Bearbeitung von Requests abgeschlossen hat**. Dadurch könnten beispielsweise Ressourcen wie Arbeitsspeicher oder eine GPU freigegeben werden. + +!!! tip "Tipp" + Das *Herunterfahren* würde erfolgen, wenn Sie die Anwendung **stoppen**. + + Möglicherweise müssen Sie eine neue Version starten, oder Sie haben es einfach satt, sie auszuführen. 🤷 + +### Lifespan-Funktion + +Das Erste, was auffällt, ist, dass wir eine asynchrone Funktion mit `yield` definieren. Das ist sehr ähnlich zu Abhängigkeiten mit `yield`. + +```Python hl_lines="14-19" +{!../../../docs_src/events/tutorial003.py!} +``` + +Der erste Teil der Funktion, vor dem `yield`, wird ausgeführt **bevor** die Anwendung startet. + +Und der Teil nach `yield` wird ausgeführt, **nachdem** die Anwendung beendet ist. + +### Asynchroner Kontextmanager + +Wie Sie sehen, ist die Funktion mit einem `@asynccontextmanager` versehen. + +Dadurch wird die Funktion in einen sogenannten „**asynchronen Kontextmanager**“ umgewandelt. + +```Python hl_lines="1 13" +{!../../../docs_src/events/tutorial003.py!} +``` + +Ein **Kontextmanager** in Python ist etwas, das Sie in einer `with`-Anweisung verwenden können, zum Beispiel kann `open()` als Kontextmanager verwendet werden: + +```Python +with open("file.txt") as file: + file.read() +``` + +In neueren Versionen von Python gibt es auch einen **asynchronen Kontextmanager**. Sie würden ihn mit `async with` verwenden: + +```Python +async with lifespan(app): + await do_stuff() +``` + +Wenn Sie wie oben einen Kontextmanager oder einen asynchronen Kontextmanager erstellen, führt dieser vor dem Betreten des `with`-Blocks den Code vor dem `yield` aus, und nach dem Verlassen des `with`-Blocks wird er den Code nach dem `yield` ausführen. + +In unserem obigen Codebeispiel verwenden wir ihn nicht direkt, sondern übergeben ihn an FastAPI, damit es ihn verwenden kann. + +Der Parameter `lifespan` der `FastAPI`-App benötigt einen **asynchronen Kontextmanager**, wir können ihm also unseren neuen asynchronen Kontextmanager `lifespan` übergeben. + +```Python hl_lines="22" +{!../../../docs_src/events/tutorial003.py!} +``` + +## Alternative Events (deprecated) + +!!! warning "Achtung" + Der empfohlene Weg, das *Hochfahren* und *Herunterfahren* zu handhaben, ist die Verwendung des `lifespan`-Parameters der `FastAPI`-App, wie oben beschrieben. Wenn Sie einen `lifespan`-Parameter übergeben, werden die `startup`- und `shutdown`-Eventhandler nicht mehr aufgerufen. Es ist entweder alles `lifespan` oder alles Events, nicht beides. + + Sie können diesen Teil wahrscheinlich überspringen. + +Es gibt eine alternative Möglichkeit, diese Logik zu definieren, sodass sie beim *Hochfahren* und beim *Herunterfahren* ausgeführt wird. + +Sie können Eventhandler (Funktionen) definieren, die ausgeführt werden sollen, bevor die Anwendung hochgefahren wird oder wenn die Anwendung heruntergefahren wird. + +Diese Funktionen können mit `async def` oder normalem `def` deklariert werden. + +### `startup`-Event + +Um eine Funktion hinzuzufügen, die vor dem Start der Anwendung ausgeführt werden soll, deklarieren Sie diese mit dem Event `startup`: + +```Python hl_lines="8" +{!../../../docs_src/events/tutorial001.py!} +``` + +In diesem Fall initialisiert die Eventhandler-Funktion `startup` die „Datenbank“ der Items (nur ein `dict`) mit einigen Werten. + +Sie können mehr als eine Eventhandler-Funktion hinzufügen. + +Und Ihre Anwendung empfängt erst dann Anfragen, wenn alle `startup`-Eventhandler abgeschlossen sind. + +### `shutdown`-Event + +Um eine Funktion hinzuzufügen, die beim Herunterfahren der Anwendung ausgeführt werden soll, deklarieren Sie sie mit dem Event `shutdown`: + +```Python hl_lines="6" +{!../../../docs_src/events/tutorial002.py!} +``` + +Hier schreibt die `shutdown`-Eventhandler-Funktion eine Textzeile `"Application shutdown"` in eine Datei `log.txt`. + +!!! info + In der Funktion `open()` bedeutet `mode="a"` „append“ („anhängen“), sodass die Zeile nach dem, was sich in dieser Datei befindet, hinzugefügt wird, ohne den vorherigen Inhalt zu überschreiben. + +!!! tip "Tipp" + Beachten Sie, dass wir in diesem Fall eine Standard-Python-Funktion `open()` verwenden, die mit einer Datei interagiert. + + Es handelt sich also um I/O (Input/Output), welches „Warten“ erfordert, bis Dinge auf die Festplatte geschrieben werden. + + Aber `open()` verwendet nicht `async` und `await`. + + Daher deklarieren wir die Eventhandler-Funktion mit Standard-`def` statt mit `async def`. + +### `startup` und `shutdown` zusammen + +Es besteht eine hohe Wahrscheinlichkeit, dass die Logik für Ihr *Hochfahren* und *Herunterfahren* miteinander verknüpft ist. Vielleicht möchten Sie etwas beginnen und es dann beenden, eine Ressource laden und sie dann freigeben usw. + +Bei getrennten Funktionen, die keine gemeinsame Logik oder Variablen haben, ist dies schwieriger, da Sie Werte in globalen Variablen speichern oder ähnliche Tricks verwenden müssen. + +Aus diesem Grund wird jetzt empfohlen, stattdessen `lifespan` wie oben erläutert zu verwenden. + +## Technische Details + +Nur ein technisches Detail für die neugierigen Nerds. 🤓 + +In der technischen ASGI-Spezifikation ist dies Teil des Lifespan Protokolls und definiert Events namens `startup` und `shutdown`. + +!!! info + Weitere Informationen zu Starlettes `lifespan`-Handlern finden Sie in Starlettes Lifespan-Dokumentation. + + Einschließlich, wie man Lifespan-Zustand handhabt, der in anderen Bereichen Ihres Codes verwendet werden kann. + +## Unteranwendungen + +🚨 Beachten Sie, dass diese Lifespan-Events (Hochfahren und Herunterfahren) nur für die Hauptanwendung ausgeführt werden, nicht für [Unteranwendungen – Mounts](sub-applications.md){.internal-link target=_blank}.