Planen mehrerer Programme mit einem Klick — Überschreitung der 15-Minuten-Grenze von AWS Lambda
Ein FAST-Kanalbetreiber plant einen Monat Programm und klickt einmal auf Deploy. Hinter diesem einzigen Klick werden Hunderte von Programmen zu Tausenden von MediaLive-Zeitplanaktionen, die in AWS der Reihe nach landen müssen, alle innerhalb der 15-minütigen Ausführungsobergrenze von Lambda — und jeder Fehler mittendrin hinterlässt einen Live-Kanal mit Lücken. Hier erfahren Sie, wie wir die Ein-Klick-Bereitstellung großer Wiedergabelisten zuverlässig gemacht haben und warum der nächste Schritt eine andere Laufzeitumgebung ist und nicht eine größere Lambda.
KurzĂĽbersicht
| Aspekt | Detail |
|---|---|
| Laufzeitumgebung | AWS Lambda (einzelner Aufruf), 615s Backend-Timeout |
| Ausgabeziel | MediaLive BatchUpdateScheduleCommand |
| Batchverarbeitung | Bis zu 200 MediaLive-Aktionen pro Anfrage — ~25 Programme in der Praxis |
| Aktionen pro Programm | ~7–8 (Input-Switch + 4 Wasserzeichen pro Rendition + 2 SCTE-35), mehr mit Werbeunterbrechungen |
| Fallback | Wiederholung pro Programm bei jeder Batch-Ablehnung |
| Beobachtet | 195 Programme in ~44 Sekunden bereitgestellt (lokale Messung) |
| Dokumentiertes Ziel | 360 Programme in ≤90 Sekunden |
| Skalierungspfad | Step Functions Chunking für Wiedergabelisten von >1 Monat — geplant, nicht ausgeliefert |
Die Herausforderung
Eine Wiedergabeliste bereitzustellen ist kein einfacher Schreibvorgang, sondern eine Orchestrierung. Für jedes vom Betreiber geplante Programm muss MediaLive genau wissen, wann die Eingänge umgeschaltet, wann das Wasserzeichen für jede Rendition aktiviert, wann SCTE-35 Cue Points eingefügt und wann Anzeigen gespleißt werden sollen. Die strukturellen Belastungen sind:
- Die Anzahl der Aktionen ist multiplikativ, nicht additiv. Jedes Programm sendet ~7–8 Aktionen vor Werbeunterbrechungen — einen Input-Switch, vier Wasserzeichen-Aktivierungen (eine pro Rendition, da StaticImageOutputActivate Ausgabepixelkoordinaten verwendet) und zwei SCTE-35 Marker. Werbeunterbrechungen fügen jeweils drei weitere Aktionen hinzu. Ein Monat mit 360 Programmen bedeutet etwa 2.800 Aktionen auf der Leitung.
- MediaLive erzwingt die Reihenfolge pro Kanal. Zeitplanaktionen sind zeitlich verankert und referenzieren einander; Schreibvorgänge auf denselben Kanal können nicht parallelisiert werden, ohne dass die API sie als widersprüchlich ablehnt.
- AWS Lambda hat eine feste 15-Minuten-Obergrenze. Keine weiche Grenze, keine Konfiguration. Der Orchestrator muss innerhalb dieser Grenze fertig sein, sonst ist der Kanal nur halb bereitgestellt.
- Teilweises Fehlschlagen ist operativ inakzeptabel. Wenn Programm 174 von 360 fehlschlägt und der Vorgang abgebrochen wird, hat der Bediener keine Diff-Ansicht dessen, was erfolgreich war und was nicht. Der Kanal geht mit Lücken live; Zuschauer sehen eine Tafel, wo sie Inhalte erwarteten.
- Die erste Version sendete einen BatchUpdateSchedule pro Programm mit einer 200ms Pause zwischen den Programmen. Das sind ~2,5 Sekunden Realzeit pro Programm. Bei 360 Programmen ĂĽberschreitet man bereits die Lambda-Obergrenze, bevor MediaLive ĂĽberhaupt echte Arbeit geleistet hat.
Die Aufgabe ist also nicht, schneller zu schreiben. Es geht darum, weniger oft zu schreiben, teilweise Fehler zu überstehen und innerhalb eines Aufrufs zu bleiben — ohne die von MediaLive geforderten Reihenfolgegarantien zu verlieren.
Warum bestehende Ansätze scheitern
Die offensichtlichen Auswege scheitern alle aus strukturellen GrĂĽnden, nicht wegen Tuning-Problemen.
- „Einfach das Lambda-Timeout erhöhen.“ Das geht nicht. Fünfzehn Minuten sind eine von AWS auferlegte feste Obergrenze für die Lambda-Ausführung; es ist keine Einstellung in der Konsole. Selbst wenn es so wäre, steigen die Kosten pro Programm mit dem Katalog — mehr Realzeit zu erkaufen, verschiebt die nächste Grenze nur.
- „Auf ECS Fargate oder EC2 umsteigen.“ Wir haben es in Betracht gezogen und abgelehnt. Langlebige Container bedeuten, dass wir die Laufzeitumgebung selbst verwalten: Health Checks, Autoscaling, Kompromisse zwischen Kaltstart und Warm-Pool, IAM-Bereich und Bereitschaftsdienst für einen Dienst, der in Bursts läuft. Lambda bietet uns Isolierung pro Aufruf und keine Leerlaufkosten für eine von Natur aus bursty Workload. Wir waren nicht bereit, das aufzugeben, um einen Engpass zu beheben.
- „MediaLive-Schreibvorgänge parallelisieren.“ MediaLive serialisiert Zeitplanaktualisierungen pro Kanal. Gleichzeitige BatchUpdateSchedule-Aufrufe für denselben Kanal führen zu Race Conditions auf der Aktionszeitlinie und werden abgelehnt. Die einzige legitime Parallelisierung ist innerhalb eines Batches, nicht über Batches hinweg.
- „Einfach abstürzen lassen und den Bediener es erneut versuchen lassen.“ Das ist die schlechteste Option. Wenn eine Bereitstellung bei Programm N abbricht, befindet sich der Kanal in einem Zustand, den niemand über die Benutzeroberfläche beschreiben kann. Bediener erhalten keine Diff-Ansicht; sie erhalten eine Black Box und einen Live-Kanal mit Lücken. Das System muss entweder alles bereitstellen oder Teilergebnisse mit einem Status pro Programm, auf den der Bediener reagieren kann.
Der Hebel, der uns blieb, war die Gestaltung der Arbeit selbst: weniger, größere Schreibvorgänge, seriell ausgeführt, mit einem Fallback, das nur bei Ablehnung eines Batches auf Zeilen-Granularität zurückfällt.
Unsere Lösung
Die Kosten vor dem Start der Schleife aus Lambda verlagern, die MediaLive-Schreibvorgänge innerhalb der Schleife zusammenfassen und nur bei Fehlschlagen eines Batches auf die Übermittlung pro Programm zurückfallen. Drei Ideen, in dieser Reihenfolge — und eine bewusste Entscheidung, dass die 15-Minuten-Obergrenze für die Kataloggrößen, die wir heute tatsächlich bereitstellen, ausreicht. Wenn Wiedergabelisten eine einzelne Ausführung übersteigen, ist die Antwort keine größere Lambda; es ist eine andere Laufzeitumgebung.

Architektur
- NestJS Backend (schedule.service.ts) — wärmt die Bereitstellung vor: eine Mongo-Roundtrip für alle einzigartigen Videos, eine für alle Ad-Marker, dann paralleles ffprobe über einzigartige Video-URLs, wobei die Ergebnisse für die Anreicherungsschleife zwischengespeichert werden.
- Lambda-Orchestrator (fastChannel-lambda-fun/index.js) — verantwortet die Batch-Schleife, die Drosselung pro Batch, den Fallback pro Programm und die Bereinigung verwaister Elemente.
- MediaLive BatchUpdateScheduleCommand — die einzige Schreiboberfläche. Jede Aktion — Input-Switch, Wasserzeichen, SCTE-35, Werbesplit — läuft darüber.
- MongoDB — die Quelle der Wahrheit für Programme, Videos und Ad-Marker; wird niemals innerhalb der inneren Schleife abgefragt.
- scheduleResults Map — Status scheduled / error pro Programm, der an das Backend zurückgegeben wird, damit der Bediener einen Diff erhält und keinen Stack Trace.
Wichtige technische Entscheidungen
1. Langsame Vorgänge vor dem Schleifenstart vorwärmen. Der ursprüngliche Code führte in der Anreicherungsschleife einen Mongo-Lookup pro Zeitplan und einen ffprobe-Aufruf pro Zeitplan durch — ein klassisches N+1, zweimal bezahlt. Das aktuelle Backend ruft jedes einzigartige Video und jeden Ad-Marker in einem Roundtrip ab, führt dann ffprobe parallel über einzigartige URLs aus und speichert das Ergebnis in einem Auflösungscache. Die innere Schleife wird zu einem Cache-Hit. Die ffprobe-Latenz wird einmal pro einzigartiger URL bezahlt, nicht seriell in der Schleife.
2. MediaLive-Schreibvorgänge zu Batches von ~25 zusammenfassen. Im Orchestrator sammeln sich Aktionen in einem einzigen BatchUpdateScheduleCommand an, bis 200 Aktionen in der Warteschlange sind oder das letzte Programm erreicht ist. Da jedes Programm ~7–8 Aktionen erzeugt, landen Batches naturgemäß bei etwa 25 Programmen pro Batch. Die Obergrenze von 200 Aktionen wurde konservativ gewählt, um deutlich unter den Nutzlastlimits von MediaLive pro Anfrage zu bleiben und die Wahrscheinlichkeit einer Ablehnung eines Batches aufgrund der Größe zu reduzieren — groß genug, um die Netzwerkkosten zu amortisieren, klein genug, um den Fallback pro Programm (nächste Entscheidung) günstig zu machen, wenn er ausgeführt werden muss. Ein Netzwerk-Roundtrip ersetzt fünfundzwanzig. Die 200ms Drosselung, die früher zwischen jedem Programm lag, liegt nun zwischen jedem Batch.
3. Batching für Geschwindigkeit, Fallback für Korrektheit. Das Zusammenfassen ist nur sicher, wenn ein einzelnes fehlerhaftes Programm die anderen vierundzwanzig in seinem Batch nicht „vergiftet“. Wenn submitProgramBatch einen Fehler wirft, ruft der Catch retryBatchAsIndividuals auf, der jedes Programm im fehlgeschlagenen Batch als eigenen BatchUpdateScheduleCommand erneut übermittelt, den Status status: 'scheduled' oder status: 'error' pro Programm aufzeichnet, 200 ms zwischen den Versuchen wartet und die Aktionszeitlinie nach jedem Teilerfolg neu verankert. Der schnelle Pfad ist gebatcht. Der Wiederherstellungspfad ist granular. Der Bediener erhält in jedem Fall einen Diff pro Programm.
4. Verwaiste Elemente am Ende bereinigen, nicht während des Betriebs verhindern. sweepIncompleteProgramGroups wird einmal am Ende der Bereitstellung ausgeführt und entfernt alle Aktionsgruppen, die keinen sauberen Endzustand erreicht haben. Wir versuchen bewusst nicht, den Kanal während der Schleife intern konsistent zu halten — das würde einen Rollback-Pfad bedeuten, der selbst in das 15-Minuten-Budget passen müsste. Die Bereinigung ist ein einmaliger Sweep, keine Transaktion.
5. Lambda nicht vergrößern; ersetzen, wenn der Katalog es tut. Für alles, was wir heute bereitstellen, wird der Einzelaufrufpfad weit innerhalb des Budgets abgeschlossen. Die ehrliche Skalierung ist das Chunking von Step Functions — die Wiedergabeliste partitionieren, Chunks als parallele Zustandsautomaten ausführen, neu zusammensetzen. Das ist der Pfad für Wiedergabelisten von über 1 Monat und 6 Monaten. Es ist entworfen, aber nicht bereitgestellt. Es als nächsten Schritt zu bezeichnen, ist nützlicher, als so zu tun, als würde es bereits laufen.
Ergebnisse
- Bei internen Tests wurde eine Bereitstellung von 195 Programmen in ca. 44 Sekunden abgeschlossen — eine Reduzierung gegenüber dem mehrminütigen, Einzelprogramm-Basiswert.
- Das dokumentierte Ziel für eine 360-Programm (~1 Monat) Wiedergabeliste ist ≤90 Sekunden, bequem innerhalb des 615-Sekunden-Backend-Timeouts und der 15-Minuten-Lambda-Obergrenze.
- Ein fehlerhaftes Programm in einem Batch bricht die anderen 24 nicht mehr ab. Der Bediener erhält eine Statusübersicht pro Programm von jeder Bereitstellung zurück.
- Die langsamen Teile der Anfrage — Mongo-Lookups und ffprobe — werden einmal pro einzigartiger Ressource bezahlt, nicht einmal pro Zeitplaneintrag.
- Die 15-Minuten-Obergrenze ist kein limitierender Faktor mehr für die Kataloggrößen, die wir tatsächlich ausliefern. Wenn sie es wieder wird, ist Step Functions Chunking die Antwort, nicht eine größere Lambda.
Technologie-Stack: AWS Lambda · AWS MediaLive · NestJS · MongoDB · Node 18 · ffprobe · TypeScript · AWS SDK v3

