Adrian RomoAdrian Romo
Alle Texte
Projekt-Log 3 Min. Lesezeit

Sechs Beiträge am Tag und der Scheduler, der lernte, wann er sagen soll

Eine Social-Pipeline, die jeden Tag genau einen Reel veröffentlicht hat und sonst nichts, weil die Quoten pro Format als Obergrenzen galten und niemand die anderen Formate nachgefragt hat.

Meine Short-Form-Pipeline veröffentlicht sechs Beiträge pro Tag auf einem Account, in vier verschiedenen Formaten. Vom „Video wird gerendert“ bis zum „Tag füllen“ hat es länger gedauert als das Erstellen des Generators, und fast keine dieser Arbeiten war kreativ.

Vier Formate, nicht eins

Der Account postet eine Verse Card in den Feed, eine Story, die das Zwillingselement dieser Card ist, zwei Standalone-Stories, ein Carousel und ein Reel. Sechs Items, vier Formate, jedes mit eigenem Generator-Pfad und eigener Vorstellung davon, was „gut“ bedeutet.

Der Zwilling ist der knifflige. Es ist derselbe Vers und dieselbe Grafik wie die Morning-Feed-Card, aber die API der Plattform erlaubt nicht, das Feed-Medium für eine Story wiederzuverwenden — also muss es als separates Medium veröffentlicht werden, das zufällig identisch aussieht. Die Artwork wird wiederverwendet statt neu generiert, daher kostet der Zwilling keine GPU-Zeit. Diese Unterscheidung zwischen Neugenerieren und Wiederverwenden ist der ganze Grund, warum er günstig ist.

Quoten waren Obergrenzen, aber keine Untergrenzen

Wochenlang veröffentlichte der Account genau ein Reel pro Tag und sonst nichts. Jede Quote war korrekt. Der Scheduler funktionierte.

Die Quoten pro Format waren nur Obergrenzen — sie verhinderten, dass Formate sich gegenseitig Slots wegnehmen. Aber der einzige Worker, der überhaupt etwas produzierte, war der Article Worker, und der macht nur Reels. Niemand im System war dafür zuständig, eine Card oder ein Carousel anzufordern. Ein Limit ist keine Anfrage, und ich hatte fünf Limits und eine Anfrage gebaut.

Die Frequenz des Timers ist nicht die Taktung

Drei Dinge, die gleich aussehen, aber nicht gleich sind:

  • Der Timer entscheidet, wie oft der Scheduler aufwacht (dreimal am Tag).
  • Der Plan entscheidet, wie viele Items jedes Formats der Tag enthalten soll.
  • Das Zeitfenster entscheidet, zu welcher Tageszeit das Item tatsächlich gepostet wird.

Der Scheduler produziert maximal ein Item pro Format pro Lauf. Also begrenzt der Timer stillschweigend den Plan: Wenn man vier Stories pro Tag anfragt, der Scheduler aber nur dreimal läuft, passiert die vierte nie, und es gibt keinen Fehler. Eine Zahl an einer Stelle zu erhöhen, erforderte, eine zweite Zahl zu erhöhen, und der Fehlerfall des Vergessens war ein unterlieferter Tag, der in den Logs völlig gesund aussah.

Zeitfenster und warum eine feste Stunde plus Jitter trotzdem nach Roboter aussieht

Jedes Format deklariert ein Zeitfenster, und die Postzeit ist eine gleichverteilte Zufallsziehung innerhalb dieses Fensters — nicht eine feste Stunde mit hinzugefügtem Rauschen. Eine feste Stunde plus Jitter clustert immer noch auf dieselbe Minute, was genau so wirkt, wie es ist.

Formate können mehrere Fenster angeben, kommasepariert, und das N-te Item des Tages zieht aus dem N-ten Fenster. Das gibt es, weil drei Stories sich kein Fenster teilen können: Der zweite Lauf des Tages würde den Großteil eines geteilten Fensters schon in der Vergangenheit finden, die Story auf morgen verschieben und einen Post kosten, während alle Ledger und Dashboards völlig in Ordnung aussahen.

Die Ziehung muss außerdem aus dem Teil des Fensters kommen, der noch über der minimalen Vorlaufzeit für die Planung liegt, nicht aus dem ganzen Fenster mit anschließendem „reject-if-too-early“-Test. Die Variante mit Ablehnung hat den ganzen Tag bei einer unglücklichen Ziehung verworfen — der 11:45-Lauf, der ein 12:00-Fenster öffnet, schlug etwa jeden achten Tag fehl. Gleiche Absicht, gleiches Fenster, komplett unterschiedliche Zuverlässigkeit.

Die Fenster sind Priors, keine Messwerte

Morgens für Andachtsinhalte, abends für Reel und Carousel, weil Sessions länger sind und Reels nach Watch Time ranken. Beides sind vernünftig klingende Vermutungen, die ich mir ausgedacht habe. Sie sind im Runbook als Vermutungen gekennzeichnet, und der Plan ist, sie durch Reichweite nach Stunden-Buckets zu ersetzen, sobald genügend Daten gesammelt sind.

„Das ist ein Prior, kein Messwert“ neben eine Zahl zu schreiben, ist der günstigste Ehrlichkeitsmechanismus, den ich kenne. Es kostet einen Satz und verhindert, dass eine Vermutung sechs Monate später zur Tatsache wird.

Was ich tatsächlich falsch gemacht habe

Das Runbook für diese Pipeline widersprach sich vom Tag an, an dem ich es schrieb. Eine Tabelle sagte zwei Stories pro Tag; ein Abschnitt hundertfünfzig Zeilen früher argumentierte, dass eine Story pro Tag eine bewusste Entscheidung sei; die Live-Konfiguration sagte eins. Außerdem beschrieb es die Pipeline als unbeaufsichtigt Reels veröffentlichend, obwohl das Flag, das das ermöglicht hätte, nie gesetzt wurde — der Reel-Slot war also jeden einzelnen Tag leer, an dem behauptet wurde, er sei voll.

Dokumentation driftet vom System weg. Das ist normal und erwartet. Das hier war schlimmer: Das Dokument war nie wahr und intern so inkonsistent, dass es jeder, der es von oben bis unten liest, bemerkt hätte. Ich habe es nicht von oben bis unten gelesen, weil ich es selbst geschrieben habe.

Geschrieben von

Adrian Romo

Senior Backend Engineer für skalierbare Python-APIs, AWS-Lambda-Architekturen, Voice-Systeme und Enterprise-Integrationen.

Weiter geht's

Wohin als Nächstes?

Stöbere durch weitere technische Texte, sieh dir die Engineering Case Studies an oder melde dich direkt.