Satu Input, Ratusan Program — Menjalankan FAST Channels 24/7 di MediaLive
FAST channel 24/7 menayangkan ratusan program unik setiap hari, setiap hari, selamanya. AWS MediaLive membatasi satu channel pada 20 input attachments. Desain naif — satu input per video — kehabisan slot sebelum makan siang dan memaksa restart channel yang membuat live stream offline. Kami menyelesaikan ini dengan satu input dinamis yang melayani setiap program yang akan dimainkan channel, dan lapisan orkestrasi tingkat program di atasnya yang menjaga timeline tetap dapat menyembuhkan diri sendiri selama deploy, kegagalan parsial, dan pengeditan operator.
Ini adalah cerita rekayasa tentang bagaimana orkestrasi itu benar-benar bekerja.
Gambaran Singkat
| Aspek | Detail |
|---|---|
| Domain | Orkestrasi FAST channel 24/7 di AWS MediaLive |
| Input attachments per channel | 1 dinamis + 1 slate (+ SRT opsional) — jauh di bawah batas 20-input |
| Identitas per-program | 8-byte hex programId tertanam dalam setiap nama aksi |
| Ambang batas pengisian slate | Kesenjangan ≥ 6 detik mendapatkan aksi slate-switch |
| Kapasitas jadwal | 1500 aksi per channel (batas keras AWS, preflighted) |
| Self-healing | Orphan-action sweep berjalan setelah setiap deploy |
| Status | Dalam produksi |
Masalah Bisnis
FAST channel adalah layanan 24/7. Operator menjadwalkan satu minggu atau bulan penuh video unik di muka, dan channel harus memutar setiap satu pada detik yang tepat — mengganti sumber dengan bersih, menjaga watermark tetap stabil, mengeluarkan isyarat jeda iklan, mengisi celah dengan slate bermerk stasiun. Penonton tidak boleh melihat frame hitam, logo yang macet, atau program minggu lalu yang berulang.
Orkestrasi tersebut harus bertahan dari segala hal yang dilakukan operator: mengedit lineup besok, menambahkan jeda iklan di tengah minggu, mendistribusikan kembali setelah satu program gagal, berlomba dengan dua klik Deploy. Sistem harus menerapkan setiap perubahan secara atomik terhadap channel langsung atau pulih dengan bersih. "Channel sekarang dalam keadaan yang tidak dipahami siapa pun" bukanlah hasil yang dapat diterima pada infrastruktur yang sedang mengudara secara langsung.
Primer MediaLive 60 Detik
AWS MediaLive adalah encoder cloud jangka panjang. Anda memberinya satu atau lebih input (stream sumber atau URL file) dan jadwal tindakan terjadwal — beralih ke input ini, nyalakan overlay ini, masukkan isyarat ini. Encoder berjalan selamanya, mengeksekusi tindakan pada waktu yang dijadwalkan dan mengeluarkan manifest HLS yang dikonsumsi oleh pemutar penonton.
Dua batasan AWS membentuk segala sesuatu di hilir:
- 20 input attachments per channel. Batas keras. Channel "Top 20 movies" yang dirancang secara naif dengan satu input per video mengisi batas pada film ke-21.
- 1500 tindakan jadwal per channel. Juga batas keras. Setiap program adalah beberapa tindakan (pergantian input, watermark per rendition, isyarat iklan, pergantian slate), jadi batas sebenarnya lebih dekat dengan beberapa ratus program pada satu waktu.
Kedua batasan ini penting untuk channel 24/7 yang diharapkan memutar konten unik tanpa batas waktu.
Mengapa Pendekatan Naif Gagal
Jalur-jalur yang jelas masing-masing rusak dengan cara yang berbeda:
- "Satu input per program." menyelesaikan batas 20-attachment hari pertama. Menambahkan lebih banyak memerlukan pembuatan ulang channel — dan pembuatan ulang channel memakan waktu 60–90 detik selama live stream hilang. Tidak dapat diterima pada layanan 24/7.
- "Buat ulang channel untuk setiap deploy." Masalah yang sama, setiap deploy. Penonton mengalami gangguan setiap kali program berubah. Ini bukan pilihan nyata untuk channel yang seharusnya live.
- "Pra-encode seluruh minggu menjadi satu file looping raksasa." Membunuh model pengeditan. Ingin mengatur ulang besok? Encode ulang seluruh minggu. Ingin memasukkan iklan? Encode ulang. Alasan utama FAST channel bekerja sebagai bisnis adalah pemrograman dinamis dan penyisipan iklan per-jeda — membakar semuanya menjadi satu file menutup kedua hal tersebut.
- "Jalankan beberapa channel secara paralel." Membutuhkan pemutar untuk beralih di antara mereka, melipatgandakan biaya AWS, dan memecah pipeline audio, MediaPackage, dan CDN. Tidak menyelesaikan masalah melainkan melipatgandakannya.
Tuas yang kami miliki adalah satu fitur terdokumentasi AWS — placeholder $urlPath$ pada input dinamis — dan kebebasan untuk membangun orkestrasi apa pun yang kami inginkan di atasnya.
Mengapa ini penting. Triknya bukan menggunakan $urlPath$. AWS mendokumentasikannya. Triknya adalah membangun lapisan orkestrasi yang dapat menyembuhkan diri sendiri di atasnya yang bertahan dari deploy parsial, pengeditan operator, dan percobaan ulang bersamaan — tanpa pernah menempatkan channel langsung dalam keadaan yang tidak dapat dijelaskan siapa pun dari UI.
Solusi Kami
Satu channel MediaLive. Satu input dinamis yang terhubung ke URL tepat $urlPath$. Satu input slate untuk mengisi celah. Pada setiap batas program, aksi InputSwitchScheduleActionSettings menggantikan URL input dinamis dengan jalur S3 aktual program tersebut. Channel tidak pernah membutuhkan input attachment baru, tidak pernah membutuhkan restart, tidak pernah offline.
Pekerjaan menarik adalah lapisan orkestrasi yang berjalan di atas satu input tersebut — menamai setiap aksi dengan ID program sehingga yatim piatu dapat dibersihkan setelah kegagalan, mengisi celah ≥ 6 detik dengan slate sehingga penonton tidak pernah melihat frame yang tertahan, mengaktifkan watermark sesaat setelah setiap pergantian input sehingga overlay tidak berkedip melalui frame buffering, dan preflighting terhadap batas 1500-aksi sehingga deploy gagal di UI daripada di tengah penerbangan di AWS.
Diagram 1 · Arsitektur Channel
Arsitektur
- Input slate — aset statis yang terpasang pada channel untuk mengisi celah antara program.
- Input dinamis — dibuat sekali dengan Sources: [{ Url: "$urlPath$" }], Type: MP4_FILE. URL adalah placeholder; jalur aktual disuplai per program pada waktu jadwal.
- Orkestrator Lambda (fastChannel-lambda-fun/index.js) — memiliki setiap aktivitas yang muncul di channel. Menghasilkan 8-byte hex programId per program dan menandai setiap aksi terkait dengannya.
- Jadwal MediaLive — daftar tindakan terurut tunggal, semuanya mengalir melalui satu BatchUpdateScheduleCommand. Dibatasi pada 1500 tindakan oleh AWS.
- Preflight backend (schedule.service.ts) — memanggil GET_SCHEDULE_COUNT Lambda sebelum setiap deploy dan menolak untuk melanjutkan jika tindakan baru akan melebihi batas.
Orphan sweep (sweepIncompleteProgramGroups) — berjalan setelah setiap deploy. Mengelompokkan tindakan berdasarkan programId, menghapus setiap kelompok yang kehilangan aksi input-switch-nya.
Keputusan Rekayasa Utama
1. Satu input dinamis, satu override URL per program
Input dinamis dibuat dengan Sources: [{ Url: "$urlPath$" }]. Pada setiap batas program, Lambda mengeluarkan aksi InputSwitchScheduleActionSettings yang menyuplai UrlPath: [program.videoUrl] — URL S3 aktual dari MP4 program tersebut. MediaLive menggantikan placeholder pada waktu eksekusi dan menarik dari sumber yang sebenarnya.
Satu input attachment sekarang melayani setiap program yang akan dimainkan channel — video unik yang secara efektif tidak terbatas selama masa hidup channel, dibatasi hanya oleh batas tindakan jadwal per-deploy pada satu titik waktu. Batas 20-input tidak lagi menjadi kendala, dan channel tidak pernah membutuhkan restart untuk menambahkan konten baru.
Diagram 2 · Override URL Input Dinamis

Tradeoff yang sengaja kami buat. Input dinamis tidak memvalidasi URL sebelumnya — MediaLive hanya menyelesaikan placeholder pada waktu pergantian, sehingga 404 muncul sebagai kesalahan sisi stream daripada penolakan waktu deploy. Kami menerima biaya itu sebagai imbalan atas kesederhanaan arsitektur dari satu input. Validasi ffprobe terpisah dari backend menangkap sumber yang salah bentuk sebelum deploy.
2. Nama aksi yang ditandai program memungkinkan self-healing
Setiap aksi yang dikeluarkan oleh Lambda membawa 8-byte hex programId program dalam namanya: input-switch-${programId}, watermark-on-${programId}-${rendition}, ad-break-start-${programId}-${i}, program-end-${programId}, slate-switch-${programId}.
Setelah setiap deploy, sweepIncompleteProgramGroups mencantumkan setiap aksi yang saat ini ada di channel, mengelompokkan mereka berdasarkan programId yang tertanam, dan menghapus setiap kelompok yang aksi input-switch-nya hilang. Itulah jalur pembersihan untuk deploy parsial yang gagal, pengeditan yang berlomba, dan kondisi lain yang dapat meninggalkan channel dengan setengah tindakan program yang terdampar.
Pengkodean nama aksi adalah seluruh mekanisme identitas. MediaLive sendiri tidak memiliki konsep "program" — lapisan orkestrasi memproyeksikannya ke atasnya melalui konvensi penamaan.
Mengapa ini penting. Tanpa ID program yang tertanam dalam setiap nama aksi, orphan sweep tidak akan memiliki cara untuk mengetahui tindakan mana yang saling terkait. Pembersihan tingkat aksi akan menghapus terlalu banyak (reset seluruh channel) atau terlalu sedikit (watermark yang terdampar yang tidak pernah mati). Konvensi penamaan adalah model data.
3. Aturan slate 6 detik
Program jarang bersebelahan dengan sempurna — hampir selalu ada celah beberapa detik antara akhir satu MP4 dan awal program berikutnya yang dijadwalkan. Orkestrasi mengeluarkan aksi slate-switch setiap kali celah tersebut ≥ 6 detik (MIN_SLATE_GAP_MS = 6000).
Ambang batas tidak sembarangan. MediaLive memberlakukan jarak minimum 5 detik antara dua tindakan jadwal apa pun; mengeluarkan slate-switch lebih dekat dari itu ke pergantian input program berikutnya menghasilkan penolakan. Aturan 6 detik memberi MediaLive celah yang diperlukan dan meninggalkan lapisan orkestrasi satu detik margin keamanan drift jam. Di bawah 6 detik, kami membiarkan frame terakhir program sebelumnya membeku sebentar daripada mengambil risiko penolakan deploy.
4. Watermark per-rendition dengan penundaan aktivasi terukur
Watermark adalah aksi StaticImageOutputActivate yang dikeluarkan per output rendition (1080p, 720p, 480p, 360p) — empat tindakan per program. Setiap tindakan menembak 1.500 ms setelah pergantian input program tersebut.
Penundaan ada karena frame pertama setelah pergantian input masih buffering; mengaktifkan overlay pada saat pergantian yang tepat dapat menghasilkan kilatan singkat saat overlay melukis pada frame yang belum sepenuhnya dirender. 1.500 ms adalah nilai yang secara konsisten menghasilkan aktivasi bersih di semua empat rendition dalam pengujian. Ini adalah konstanta terukur, bukan parameter MediaLive yang didokumentasikan — dan itu hidup di satu tempat dalam kode sehingga penyetelan di masa depan adalah perubahan satu baris.
Tradeoff yang sengaja kami buat. Tindakan overlay per-rendition memakan biaya 4× jumlah tindakan dibandingkan dengan satu overlay global. Kami menerima biaya tersebut karena jalur per-rendition memungkinkan setiap output mendapatkan watermark yang ukurannya tepat untuk dimensi pikselnya, daripada membiarkan MediaLive menurunkan skala satu overlay di semua empat. Hasilnya adalah logo yang terlihat lebih tajam pada output SD — dan itu meninggalkan cukup anggaran tindakan untuk ratusan program sebelum batas 1500 menjadi masalah.
5. Batas 1500-aksi, preflighted di UI
AWS membatasi keras channel MediaLive pada 1500 tindakan jadwal. Dengan ~7–8 tindakan per program (pergantian input + 4 watermark + 2 isyarat iklan + slate sesekali), channel menampung sekitar 180–200 program aktif tergantung pada kepadatan iklan dan frekuensi slate. Itu adalah batas nyata untuk deploy jangka panjang, dan jumlah pastinya tergantung pada kompleksitas per-program.
Sebelum setiap deploy, backend memanggil GET_SCHEDULE_COUNT Lambda, yang menghitung tindakan langsung di channel melalui DescribeScheduleCommand dan mengembalikan { liveCount, capacity: 1500 }. Jika liveCount + (newPrograms × 8) akan melebihi 1500, backend melempar SCHEDULE_ACTION_CAP_EXCEEDED dengan jumlah ruang kepala yang tepat — sebelum mengirimkan apa pun ke MediaLive. Operator melihat batas di UI dengan panduan untuk menghapus program sebelumnya terlebih dahulu. Deploy tidak pernah setengah berjalan ke dinding.
Diagram 3 · Timeline Aksi Satu Program

Hasil
- Satu channel MediaLive melayani program unik yang secara efektif tidak terbatas selama masa hidupnya, pada satu input attachment dinamis. Batas 20-input tidak lagi menjadi kendala yang harus kami rencanakan — kapasitas pada satu waktu diatur oleh batas tindakan jadwal, bukan batas input.
- Orkestrasi channel dapat menyembuhkan diri sendiri: setiap deploy berakhir dengan orphan sweep, sehingga deploy parsial yang gagal tidak dapat meninggalkan jadwal dalam keadaan tidak konsisten.
- Kapasitas jadwal dibatasi dan terlihat. Operator melihat batas 1500-aksi di UI sebelum mereka mengklik, bukan sebagai penolakan AWS yang tidak jelas di tengah deploy.
- Konvensi penamaan ID program adalah seluruh lapisan identitas — dan itu adalah string. Tidak ada infrastruktur baru, tidak ada penyimpanan tambahan, tidak ada ketergantungan. Proyeksi paling sederhana dari "program" ke daftar tindakan datar MediaLive.
Teknologi Stack: AWS MediaLive · AWS Lambda · NestJS · MongoDB · TypeScript · Node 18 · AWS SDK v3 (@aws-sdk/client-medialive)

