Zum Inhalt springen

Blog ·

Der Kindlauf weckt den Elternlauf

Ein Flow, der einen Flow aufruft, kann fragen oder benachrichtigt werden. Wir bauten beides, und die Rückfalluhr steht aus gemessenem Grund auf einem Tag.

Von Provibr

Ein Flow kann jetzt einen anderen Flow aufrufen. Der aufrufende Lauf hält an, der aufgerufene Lauf startet, und wenn der aufgerufene Lauf fertig ist, läuft der aufrufende Lauf auf dem ok-Draht oder dem error-Draht weiter.

Die ganze Entwurfsfrage in diesem Satz steckt im Wort wann. Irgendetwas muss bemerken, dass das Kind fertig ist. Es gibt zwei Arten, das einzurichten, und wir sind bei beiden gelandet, in einer bestimmten Reihenfolge, und in der zweiten steckt eine Zahl, über die einiges zu streiten war.

Der Elternlauf wartet nicht, ihm wird es gesagt

Die natürliche Art, das zu schreiben, ist ein Elternlauf, der wartet. Der Elternlauf weiß, auf welchen Lauf er wartet, also kann er fragen. Alle zehn Sekunden abfragen, nachsehen, ob das Kind fertig ist, weiterlaufen, sobald es das ist.

Das ist verkehrt herum, und der Grund ist, dass das Kind es bereits weiß. Es ist dasjenige, das in einen Endzustand übergeht. Den Elternlauf fragen zu lassen heißt, dass die Auskunft von der Partei, die sie hat, zu der Partei, die sie braucht, über eine wiederholte Frage reist, und die Häufigkeit dieser Frage ist die Verzögerung der ganzen Funktion.

Also meldet sich das Kind. Erreicht ein Kindlauf einen Endzustand, setzt er die Weckzeit auf der Wartezeile, die auf ihn zeigt, auf jetzt, und der gewöhnliche Warteschlangen-Worker greift sie innerhalb seines nächsten Takts auf. Das ist genau derselbe Mechanismus, den eine menschliche Genehmigung benutzt: eine Entscheidung zu treffen setzt die Weckzeit auf jetzt. Eine Spalte steuert die Warteschlange, und es gibt bewusst keinen zweiten Weg in den Ausführer hinein.

Diese Meldung ist eine einzige Anweisung: die Wartezeile aktualisieren, bei der die Kennung des Kindlaufs übereinstimmt und der Status noch wartend ist.

Warum diese Kennung eine Spalte ist und nicht Teil des Zustandsklumpens

Die Fortsetzung eines pausierten Durchlaufs wird als JSON gespeichert, und sie enthält alles, was der Durchlauf zum Fortsetzen braucht: den Stapel, die besuchten Knoten, die Variablen, die Zähler. Es wäre stimmig gewesen, die Kennung des Kindes auch dort abzulegen.

Sie ist stattdessen eine Spalte, und der Grund ist die Richtung. Alles andere in diesem Klumpen wird vom Durchlauf gelesen, von innen. Dieser eine Wert wird von außen gelesen, von einem Kindlauf, der die Zeile finden will, die auf ihn zeigt. Im Klumpen ist das ein Durchsuchen jedes offenen Wartevorgangs im System, und der Index, den Sie bräuchten, um das billig zu machen, ist ohnehin diese Spalte.

Der Fremdschlüssel steht auf SET NULL statt auf CASCADE. Wird der Kindlauf aufgeräumt, darf das Warten des Elternlaufs nicht mit ihm verschwinden, denn dann ist ein Elternlauf ausgesetzt und nichts wird ihn je wecken. Den Verweis zu verlieren ist überlebbar; die Zeile zu verlieren ist es nicht.

Die Rückfalluhr steht auf einem Tag, und die Zahl ist das Argument

Die Meldung ist der Mechanismus. Die Uhr ist das Sicherheitsnetz für den Fall, dass die Meldung nie ankommt: ein Container, der auf halbem Weg durch das Fertigwerden des Kindes umgefallen ist, eine von Hand angefasste Zeile.

Der naheliegende Wert für ein Sicherheitsnetz ist etwas Kleines. Fünf Minuten fühlen sich verantwortungsvoll an.

Er ist falsch, und der Grund ist das, was ein Kind tun darf. Ein Kindlauf kann eine menschliche Genehmigung enthalten, und eine Genehmigung kann eine Frist dreißig Tage in der Zukunft haben. Mit einer Uhr von fünf Minuten wacht der Elternlauf dieses Kindes über diese dreißig Tage tausende Male auf, um festzustellen, dass sich nichts geändert hat, und jedes dieser Aufwachen ist eine HTTP-Anfrage vom Gateway an den Web-Container.

Vierundzwanzig Stunden kosten über das längste Warten hinweg, das das Produkt zulässt, höchstens dreißig sinnlose Takte und begrenzen den Schaden einer wirklich verpassten Meldung auf einen Tag. Das ist die Abwägung, ausgedrückt in den Einheiten, auf die es ankommt: wie viele Anfragen kostet das Sicherheitsnetz, wenn nichts falsch ist, gegen wie lange ein echter Ausfall unsichtbar bleibt.

Die allgemeine Gestalt: ein Wiederholungsabstand ist nicht „so kurz, wie wir es uns leisten können“. Er ist eine Funktion des längsten berechtigten Wartens, und wenn Sie nicht gefragt haben, wie lang das ist, ist der Abstand geraten.

Eine Uhr, die Sie nicht kürzen können, ist eine Uhr, die Sie nicht beweisen können

Ein Sicherheitsnetz feuert nur, wenn der Mechanismus darunter versagt hat. Mit einem auf einen Tag festgelegten Abstand dauert es einen Tag, zu zeigen, dass es funktioniert, also lieferte die Runde, die es baute, diesen Zweig als unbewiesen aus, ehrlich beschriftet.

Die Versuchung ist, ihn von Hand zu beweisen: in die Datenbank greifen, die Weckzeit in die Vergangenheit schieben, zusehen, wie der Lauf weiterläuft. Das beweist das Fortsetzen. Es beweist die Uhr nicht, denn die Uhr ist genau das, was Sie ersetzt haben.

Der Abstand liest also eine Umgebungsvariable, und der Hook lebt im Quelltext neben der Konstanten statt in einer Testdatei. Er wird von einem Ende-zu-Ende-Skript benutzt, das ihn auf ein paar Sekunden setzt, das Sicherheitsnetz wirklich feuern lässt und einen Elternlauf beobachtet, dessen Kind nie etwas gemeldet hat und der sich von selbst erholt.

Zwei Eigenschaften machen diesen Hook sicher genug, um ihn auszuliefern. Er kann den Abstand nur kürzer machen: der Wert wird gegen die Produktionskonstante geklemmt, eine falsch eingestellte Umgebung kann einen Elternlauf also nie länger als einen Tag warten lassen. Und alles, was keine positive Zahl ist, fällt auf den Produktionswert zurück.

Das Zweite ist nicht defensives Programmieren um seiner selbst willen. Kopiert man unsere Beispiel-Umgebungsdatei, ist die Variable vorhanden und leer, und eine leere Zeichenkette ist nicht undefiniert. Sie in eine Zahl umzuwandeln ergibt null. Ohne das Sieb würde eine kopierte Konfigurationsdatei den Abstand auf null setzen und jeden Elternlauf mit einem ausstehenden Kind in eine Aufwachschleife gegen den Web-Container schicken. Der Unterschied zwischen leerer Zeichenkette und undefiniert hat uns schon einmal erwischt, an einer Stelle, wo er eine Downloadroute einen 404 kostete.

Zwei Grenzen, jede zweimal durchgesetzt

Ein Flow, der einen Flow aufruft, wirft die Frage nach einem Flow auf, der sich selbst aufruft. Es gibt zwei Grenzen, Rekursion und Tiefe, und jede wird an zwei Stellen durchgesetzt.

Statisch, wenn ein Flow gespeichert wird: der Graph wird durchlaufen, die von ihm aufgerufenen Flows werden aufgelöst, und ein Zyklus oder eine zu tiefe Kette wird verweigert, wobei die Kette in der Fehlermeldung benannt wird. Dynamisch, während eines Laufs: dieselben zwei Grenzen noch einmal, mit eigenen Verweigerungscodes.

Beides ist nötig, weil Flows unabhängig voneinander bearbeitet werden. Zwei Flows, die einzeln in Ordnung sind, können in dem Moment zu einem Zyklus werden, in dem jemand dem zweiten einen Aufruf hinzufügt, und nichts prüft den ersten erneut. Die statische Prüfung ist das, was in dem Moment eine brauchbare Fehlermeldung gibt, in dem jemand es noch beheben kann; die dynamische Prüfung ist das, was tatsächlich hält.

Die Tiefe ist eine Spalte auf dem Lauf statt etwas, das durch das Ablaufen der Eltern berechnet wird. Das widerspricht der Linie, die wir sonst vertreten, nämlich dass alles Ableitbare abgeleitet werden sollte. Hier hält sie nicht, denn der Elternverweis steht auf SET NULL: sobald ein Elternlauf aufgeräumt wurde, lässt sich die Kette nicht mehr zurückverfolgen, und die Tiefe eines laufenden Kindes wäre genau in dem Moment nicht mehr feststellbar, in dem es darauf ankommt.

Was die nachfolgende Runde gemessen hat

Die Zweige, die dieser Entwurf offen ließ, wurden in einer späteren Runde genommen, und zwei davon sind die interessanten.

Ein Kindlauf, der vollständig verschwindet: das Warten behält seine Zeile und verliert seinen Verweis, die Rückfalluhr weckt den Elternlauf, und das Fortsetzen findet kein Kind und lässt diesen Knoten mit einer bestimmten Begründung scheitern, statt hängen zu bleiben. Ein Graph, der überhaupt nicht gelesen werden kann, ergibt eine andere Begründung, die beiden Situationen sind im Laufprotokoll also unterscheidbar.

Ein Subflow innerhalb einer Schleife, in den zwei Gestalten, die sich unterschiedlich verhalten: ein Kind, das innerhalb der auslösenden Anfrage fertig wird, und ein Kind, das sich selbst aussetzt. Das erste fasst die Warteschlange überhaupt nicht an. Das zweite ist die ganze Funktion.

Was wir aufschreiben würden

  1. Die Partei, die es weiß, sollte es sagen, statt gefragt zu werden. Abfragen macht aus Ihrer Verzögerung einen Konfigurationswert.
  2. Benutzen Sie den Weckpfad wieder, den Sie schon haben. Eine Entscheidung und ein fertiges Kind sind für die Warteschlange dasselbe Ereignis.
  3. Ein Wert, der von außerhalb des Zustandsklumpens gelesen wird, gehört in eine Spalte. Darüber entscheidet die Richtung und nicht die Stimmigkeit.
  4. Auf SET NULL statt auf CASCADE, wenn die Zeile, die gelöscht würde, für jemanden die einzige Möglichkeit ist, geweckt zu werden.
  5. Der Abstand eines Sicherheitsnetzes ist eine Funktion des längsten berechtigten Wartens, nicht davon, wie flink Sie sich fühlen möchten.
  6. Nennen Sie die Abwägung in Anfragen und Stunden. Dreißig verschwendete Takte gegen einen Tag Unsichtbarkeit ist eine Entscheidung; „fünf Minuten“ ist ein Reflex.
  7. Eine Konstante, die Sie nicht verändern können, ist ein Zweig, den Sie nicht beweisen können. Der Hook gehört neben die Konstante.
  8. Lassen Sie den Hook die Dinge nur sicherer machen, und klemmen Sie ihn gegen den Produktionswert.
  9. Eine leere Umgebungsvariable ist nicht undefiniert, und sie in eine Zahl umzuwandeln ergibt null.
  10. Prüfen Sie eine Grenze dort, wo sie behoben werden kann, und dort, wo sie halten muss. Unabhängig bearbeitete Graphen brauchen beides.

Zur Klarheit: die Merge-Prüfung lief 16 von 16 Schritten ohne Fehlerzeile durch, die Web-Suite war 4583 grün, Packages, Gateway und Tools zusammen 7286 grün, der Durchlauf 75 grün, die statische Subflow-Prüfung 13 grün, der Ende-zu-Ende-Lauf gegen die Entwicklungsdatenbank 58 grün, die Empfängermessung 4 grün, ein Browsertest mit einem echten Gateway-Worker 31 grün, in dem eine Pause von neunzig Sekunden nach fünfundneunzig Sekunden fortgesetzt wurde, der Editortest 9 grün, und der Barrierefreiheitsdurchlauf fand über sechs Seiten hinweg nichts. Damals nicht bewiesen: die Rückfalluhr, ein Subflow innerhalb einer Schleife, ein verschwundener Kindlauf und der Zweig für erschöpfte Wiederholungen. Diese vier wurden in der folgenden Runde genommen.

Aus der Plattformarbeit an Provibr. Wie der Durchlauf zu etwas wurde, das sich in eine Zeile schreiben lässt, steht in Jeder Selbstaufruf stand in Endposition, und die Runde, die schließlich die Zweige erreichte, die diese offen ließ, steht in Grün, weil es nicht hinkommen konnte.

Fangen Sie mit einem Host und einem Agenten an

Konto erstellen, den Agenten mit einem einzigen Befehl installieren und Ihren ersten Proxmox-Host verbinden. Die Testphase läuft 14 Tage und fragt nicht nach Zahlungsdaten.