Skip to main content
Damit ein Paket nicht nur in gewöhnlichen HTTP-Requests, sondern auch mit Octane und Queue-Workern funktioniert, müssen Sie festlegen, wie lange ein Service was halten darf. Wenn Sie requestspezifische Daten in einem Singleton speichern, kann eine andere Verarbeitung auf veraltete Daten zugreifen. Diese Seite untersucht die Implementierung des Containers, des Queue-Workers und von Octane in Laravel Framework v13.36.0 und verknüpft die grundlegenden Registrierungsmethoden des Service Containers mit der langfristigen Wartung von Paketen. Allein die Wahl von scoped() setzt weder Referenzen zwischen Objekten noch statischen Zustand vollständig zurück.

Die Registrierungsmethode nach der Haltedauer des Service wählen

Diese Tabelle vergleicht die gewöhnliche Auflösung. Sonderwege wie die Auflösung mit expliziten Parametern oder Contextual Binding sollten Sie gesondert prüfen. Auch bei bind() bleibt die Referenz bestehen, wenn Sie den abgerufenen Service in einer Eigenschaft eines anderen Singletons speichern. Die Registrierungsmethode ist eine Regel des Containers für Erzeugung und Wiederverwendung, keine Regel, die die vom Nutzer gehaltenen Objekte zwangsweise neu erstellt.

scoped kombiniert eine geteilte Registrierung mit der Erfassung der zu entfernenden Schlüssel

Das untersuchte Container::scoped() erledigt zwei Dinge:
  1. Es erfasst den Registrierungsschlüssel in scopedInstances.
  2. Es ruft singleton() auf und registriert damit ein geteiltes Binding.
Die Instanz selbst wird wie bei einem Singleton in instances gespeichert. forgetScopedInstances() entfernt für die erfassten Schlüssel die gespeicherten Instanzen per unset(). Die Erzeugungslogik des Bindings bleibt erhalten, sodass die nächste gewöhnliche Auflösung ein neues Objekt erstellen kann. Dieser Vorgang initialisiert weder die Eigenschaften des alten Objekts neu noch schreibt er Referenzen um, die andere Objekte halten. Ein altes Objekt, auf das noch eine Referenz besteht, kann weiterhin verwendet werden.

Die Grenze wird von der Ausführungsumgebung gesetzt

Der Container selbst überwacht nicht den Beginn von HTTP-Requests oder Jobs.
  • Queue-Worker: QueueServiceProvider übergibt dem Worker einen Callback, der den Scope zurücksetzt. Worker::daemon() ruft diesen in der Schleife vor dem Abrufen des nächsten Jobs auf. Im Callback werden unter anderem forgetScopedInstances() ausgeführt und die aufgelösten Instanzen der Facades geleert.
  • Octane: Die offizielle Standardkonfiguration registriert FlushTemporaryContainerInstances für OperationTerminated. Dieser Listener ruft forgetScopedInstances() auf.
  • Eigene dauerhaft laufende Befehle oder Schleifen: Das bloße Wiederholen von make() erzeugt keine Grenze. Der Lebenszyklus muss auf Seiten der Ausführungsplattform entworfen werden.
Rufen Sie forgetScopedInstances() nicht nach eigenem Ermessen aus gewöhnlicher Anwendungslogik oder aus boot() eines Pakets auf. Das betrifft alle scoped Services im gesamten Container. Außerdem durchlaufen nicht alle Job-Ausführungswege, einschließlich der synchronen Ausführung, denselben Reset-Weg wie ein dauerhaft laufender Worker.

Innerhalb einer Verarbeitung geteilten Zustand als scoped registrieren

Betrachten wir ein Versandpaket, das innerhalb eines Requests oder Jobs die ID eines Lieferziels teilen möchte. Es hält nicht direkt den HTTP-Request, sondern speichert nur den benötigten Wert.
Im Service Provider des Pakets wird bei der Erzeugung kein Zustand der nutzenden Anwendung gelesen, sondern ein leerer Context registriert.
Im Controller oder in handle() eines Jobs der nutzenden Anwendung wird die ID gesetzt, nachdem die Eingabe validiert und die Berechtigung geprüft wurde. Andere Services, die diesen Typ im selben Lebenszyklus auflösen, können auf denselben Context zugreifen.
Dieser Context ist keine Autorisierungsfunktion. Dass eine ID gesetzt werden kann, bedeutet nicht, dass der Zugriff auf dieses Lieferziel erlaubt ist. Außerdem ist scoped() keine Persistierung in einer Datenbank oder einem externen Cache. Werte für den nächsten Job übergeben Sie explizit als Daten des Jobs.
In Octane werden register() und boot() des Service Providers beim ersten Start des Workers ausgeführt. Entwerfen Sie es nicht so, dass der aktuelle Benutzer oder das aktuelle Lieferziel in boot() im Context gespeichert wird. Werte pro Verarbeitung setzen Sie erst, nachdem die Verarbeitung begonnen hat.

Referenzen von einem Singleton auf scoped Services werden nicht automatisch aktualisiert

Bei der folgenden Registrierung genügt es nicht, nur den Context als scoped zu registrieren:
Wenn DeliveryService den Context im Konstruktor in einer Eigenschaft speichert, behält er den zuerst erzeugten Context. Auch wenn der gespeicherte Context aus dem Container entfernt wird, ändert sich die Eigenschaft des bereits erzeugten DeliveryService nicht. Wählen Sie die Gegenmaßnahme passend zur Verantwortung des Service:
  1. Die pro Verarbeitung benötigten Werte als Methodenargumente übergeben. Wenn kein Zustand geteilt werden muss, ist dies am einfachsten.
  2. Auch die haltende Seite als scoped registrieren. Sowohl DeliveryService als auch der Context werden pro Verarbeitung neu erstellt.
  3. Einen Resolver übergeben, der zum Zeitpunkt der Verwendung auflöst. Wenn der Singleton beibehalten werden muss, holen Sie den benötigten Service jedes Mal aus dem aktuellen Container.
Im dritten Beispiel wird nicht der alte Context in die Closure übernommen, sondern zum Zeitpunkt des Aufrufs aufgelöst.
Der DeliveryService in diesem Beispiel muss so umgestellt werden, dass er im Konstruktor eine Closure entgegennimmt und eine API bietet, die sie bei jeder Operation aufruft. Ruft der Konstruktor den Resolver nur einmal auf und speichert das Ergebnis, ist das Problem nicht gelöst. Dies ist ein Designbeispiel, das den Container-Resolver aus der offiziellen Octane-Dokumentation auf einen paketspezifischen Context überträgt.

Auch Zustand prüfen, den scoped nicht entfernt

scoped() entfernt den folgenden Zustand nicht automatisch:
  • Werte, die zu paketeigenen statischen Eigenschaften hinzugefügt wurden
  • Referenzen auf den Context, die in einem anderen Singleton oder einer globalen Variable gespeichert sind
  • „Aktueller Benutzer“ oder „aktuelles Lieferziel“, die im Inneren eines Singletons gehalten werden
  • Referenzen, die von eigenen Facades oder Cache-Schichten gehalten werden
Unterscheiden Sie zwischen dem Reset durch die Standard-Ausführungsplattform und dem Reset paketeigenen Zustands. Die Zahl der Orte zu verringern, an denen Zustand pro Verarbeitung gehalten wird, ist einfacher, als in jeder Ausführungsumgebung eigene Aufräumlogik zu pflegen.

Tests schreiben, die im selben Container eine Grenze überschreiten

Wenn HTTP-Tests lediglich jedes Mal eine neue Anwendung erstellen, können Probleme übersehen werden, die entstehen, wenn ein dauerhaft laufender Prozess denselben Container weiterverwendet. Prüfen Sie zunächst mit dem Container allein, dass innerhalb einer Verarbeitung geteilt und nach der Grenze neu erzeugt wird. Die folgenden Tests sind im PHPUnit-Format. Der erste Test verwendet wie die offiziellen Container-Tests forgetScopedInstances() und prüft die Wirkung der Grenze, ohne den gesamten Worker zu starten.
Der zweite Test dokumentiert das Verhalten, dass Referenzen bestehen bleiben. Fügen Sie dem tatsächlichen Paket außerdem Tests hinzu, die prüfen, dass mit der gewählten Gegenmaßnahme ein neuer Context bzw. neue Werte verwendet werden. Unit-Tests des Containers allein prüfen nicht den tatsächlichen Ausführungsweg der Octane-Sandbox oder des Queue-Workers. Für jede Ausführungsumgebung, deren Unterstützung Sie zusichern, benötigen Sie zusätzlich Integrationstests mit aufeinanderfolgenden Verarbeitungen. Bei Deployments, die Registrierungsmethoden oder Service-Implementierungen ändern, laden Sie dauerhaft laufende Prozesse neu, damit der neue Code angewendet wird.

Verwandte Seiten

Hooks nach der Service-Auflösung in Paketen

Erläutert afterResolving, den Abruf geteilter Instanzen und Unterschiede bei der Konfiguration nach erneuter Auflösung.

Laravel Octane

Erläutert das Halten von Request und Container sowie Hinweise für den Betrieb dauerhaft laufender Prozesse.

Herangezogene Primärquellen

Zuletzt geändert am 14. Oktober 2026