Menjadwalkan Banyak Program dalam Satu Klik โ Mengalahkan Batas 15 Menit AWS Lambda
Seorang operator FAST channel menjadwalkan sebulan program dan menekan Deploy sekali. Di balik satu klik itu, ratusan program menjadi ribuan tindakan jadwal MediaLive yang harus mendarat di AWS secara berurutan, semuanya di dalam batas eksekusi lima belas menit Lambda โ dan setiap kegagalan di tengah meninggalkan saluran langsung dengan lubang di dalamnya. Inilah cara kami membuat penerapan satu klik dari daftar putar besar menjadi andal, dan mengapa langkah berikutnya adalah runtime yang berbeda, bukan Lambda yang lebih besar.
Tinjauan Singkat
| Aspek | Detail |
|---|---|
| Runtime | AWS Lambda (satu pemanggilan), 615s batas waktu backend |
| Target keluaran | MediaLive BatchUpdateScheduleCommand |
| Batching | Hingga 200 tindakan MediaLive per permintaan โ ~25 program dalam praktik |
| Tindakan per-program | ~7โ8 (pengalihan input + 4 watermark per-rendition + 2 SCTE-35), lebih banyak dengan jeda iklan |
| Fallback | Pengulangan per-program pada setiap penolakan batch |
| Teramati | 195 program diterapkan dalam ~44 detik (pengukuran lokal) |
| Target terdokumentasi | 360 program dalam โค90 detik |
| Jalur skala keluar | Step Functions chunking untuk daftar putar >1 bulan โ direncanakan, belum dikirim |
Tantangan
Menerapkan daftar putar bukanlah menulis โ itu adalah orkestrasi. Untuk setiap program yang dijadwalkan operator, MediaLive perlu tahu persis kapan harus mengganti input, kapan harus mengaktifkan watermark untuk setiap rendition, kapan harus memasukkan titik isyarat SCTE-35, dan kapan harus menyisipkan iklan. Tekanan strukturalnya adalah:
- Jumlah tindakan bersifat multiplikatif, bukan aditif. Setiap program menghasilkan ~7โ8 tindakan sebelum jeda iklan โ satu pengalihan input, empat aktivasi watermark (satu per rendition karena StaticImageOutputActivate menggunakan koordinat piksel output), dan dua penanda SCTE-35. Jeda iklan menambahkan tiga tindakan lagi masing-masing. Sebulan program 360 adalah sekitar 2.800 tindakan di jaringan.
- MediaLive menegakkan urutan per saluran. Tindakan jadwal diikat waktu dan merujuk satu sama lain; Anda tidak dapat melakukan penulisan paralel ke saluran yang sama tanpa API menolaknya sebagai konflik.
- AWS Lambda memiliki batas keras 15 menit. Bukan batas lunak, bukan konfigurasi. Orkestrator harus selesai di dalam dinding itu atau saluran berakhir setengah diterapkan.
- Kegagalan parsial tidak dapat diterima secara operasional. Jika program 174 dari 360 gagal dan membatalkan pelaksanaan, operator tidak memiliki tampilan perbedaan dari apa yang mendarat dan apa yang tidak. Saluran menjadi live dengan celah; pemirsa melihat slate di mana mereka mengharapkan konten.
- Versi pertama mengirim satu BatchUpdateSchedule per program dengan jeda 200ms antara program. Itu ~2,5 detik waktu dinding per program. Pada 360 program Anda sudah melewati batas Lambda sebelum MediaLive melakukan pekerjaan nyata.
Tugasnya, kemudian, bukanlah menulis lebih cepat. Itu adalah menulis lebih sedikit kali, bertahan dari kegagalan parsial, dan tetap di dalam satu pemanggilan โ tanpa kehilangan jaminan urutan yang diminta MediaLive.
Mengapa Pendekatan yang Ada Gagal
Pelarian yang jelas semuanya gagal karena alasan struktural, bukan masalah penyetelan.
- "Tinggikan saja batas waktu Lambda." Anda tidak bisa. Lima belas menit adalah batas keras yang diberlakukan AWS pada eksekusi Lambda; itu bukan tombol di konsol. Bahkan jika itu ada, biaya per-program tumbuh dengan katalog โ membeli lebih banyak waktu dinding hanya menunda dinding berikutnya.
- "Pindah ke ECS Fargate atau EC2." Kami mempertimbangkannya dan menolaknya. Kontainer yang berjalan lama berarti kami memiliki runtime: pemeriksaan kesehatan, penskalaan otomatis, tradeoff cold-start vs. warm-pool, cakupan IAM, dan rotasi on-call untuk layanan yang berjalan dalam ledakan. Lambda memberi kami isolasi per-pemanggilan dan biaya idle nol untuk beban kerja yang secara inheren meledak. Kami belum siap untuk melepaskan itu untuk memperbaiki satu hambatan.
- "Paralelkan penulisan MediaLive." MediaLive menyerialkan pembaruan jadwal per saluran. Panggilan BatchUpdateSchedule bersamaan terhadap saluran yang sama berlomba di timeline tindakan dan ditolak. Satu-satunya paralelisme yang sah adalah di dalam batch, bukan di antara batch.
- "Biarkan saja crash dan biarkan operator mencoba lagi." Ini adalah opsi terburuk. Ketika penerapan dibatalkan pada program N, saluran berada dalam keadaan yang tidak dapat dijelaskan siapa pun dari UI. Operator tidak mendapatkan perbedaan; mereka mendapatkan kotak hitam dan saluran langsung dengan lubang di dalamnya. Sistem harus mendaratkan semuanya atau mendaratkan hasil parsial dengan status per-program yang dapat ditindaklanjuti operator.
Tuas yang kami miliki adalah bentuk pekerjaan itu sendiri: lebih sedikit, penulisan yang lebih besar, dieksekusi secara serial, dengan fallback yang menurun ke granularitas tingkat baris hanya ketika batch ditolak.
Solusi Kami
Pindahkan biaya dari Lambda sebelum loop dimulai, gabungkan penulisan MediaLive di dalam loop, dan turunkan ke pengajuan per-program hanya ketika batch gagal. Tiga ide, dalam urutan itu โ dan keputusan yang disengaja bahwa batas 15 menit baik-baik saja untuk ukuran katalog yang sebenarnya kami terapkan hari ini. Ketika daftar putar tumbuh melebihi satu pemanggilan, jawabannya bukan Lambda yang lebih besar; itu adalah runtime yang berbeda.

Arsitektur
- Backend NestJS (schedule.service.ts) โ memanaskan penerapan: satu perjalanan pulang pergi Mongo untuk semua video unik, satu untuk semua penanda iklan, kemudian parallel ffprobe di seluruh URL video unik dengan hasil yang disimpan dalam cache untuk loop pengayaan.
- Orkestrator Lambda (fastChannel-lambda-fun/index.js) โ memiliki loop batching, throttle per-batch, fallback per-program, dan penyapuan yatim piatu.
- MediaLive BatchUpdateScheduleCommand โ satu-satunya permukaan penulisan. Setiap tindakan โ pengalihan input, watermark, SCTE-35, penyisipan iklan โ mengalir melaluinya.
- MongoDB โ sumber kebenaran untuk program, video, dan penanda iklan; tidak pernah diquery di dalam loop dalam.
- scheduleResults map โ status scheduled / error per-program yang dikembalikan ke backend sehingga operator mendapatkan perbedaan, bukan jejak tumpukan.
Keputusan Teknikal Kunci
1. Memanaskan hal-hal yang lambat sebelum loop berjalan. Kode asli melakukan pencarian Mongo per-jadwal dan panggilan ffprobe per-jadwal di dalam loop pengayaan โ klasik N+1 dibayar dua kali. Backend saat ini mengambil secara massal setiap video unik dan penanda iklan dalam satu perjalanan pulang pergi masing-masing, kemudian menjalankan ffprobe secara paralel di seluruh URL unik dan menyimpan hasilnya dalam cache resolusi. Loop dalam menjadi hit cache. Latensi ffprobe dibayar sekali per URL unik, bukan secara serial di dalam loop.
2. Gabungkan penulisan MediaLive menjadi batch ~25. Di dalam orkestrator, tindakan terakumulasi menjadi satu BatchUpdateScheduleCommand hingga 200 tindakan dijadwalkan atau program terakhir tercapai. Karena setiap program menghasilkan ~7โ8 tindakan, batch secara alami mendarat sekitar 25 program masing-masing. Batas 200 tindakan dipilih secara konservatif untuk tetap jauh di bawah batas payload per-permintaan MediaLive dan mengurangi kemungkinan batch ditolak karena ukuran โ cukup besar untuk mengamortisasi biaya jaringan, cukup kecil untuk membuat fallback per-program (keputusan berikutnya) murah ketika harus dijalankan. Satu perjalanan pulang pergi jaringan menggantikan dua puluh lima. Throttle 200ms yang dulu duduk di antara setiap program sekarang duduk di antara setiap batch.
3. Batching untuk kecepatan, fallback untuk ketepatan. Penggabungan hanya aman jika satu program buruk tidak meracuni dua puluh empat lainnya dalam batchnya. Ketika submitProgramBatch melempar, catch memanggil retryBatchAsIndividuals, yang mengirim ulang setiap program dalam batch yang gagal sebagai BatchUpdateScheduleCommand sendiri, mencatat status: 'scheduled' atau status: 'error' per program, tidur 200ms antara upaya, dan mengatur ulang timeline tindakan setelah setiap keberhasilan parsial. Jalur cepat adalah batch. Jalur pemulihan adalah granular. Operator mendapatkan perbedaan per-program dalam kedua cara.
4. Sapu yatim piatu di akhir, jangan mencegahnya saat terbang. sweepIncompleteProgramGroups berjalan sekali di akhir penerapan dan menghapus setiap grup tindakan yang tidak mencapai keadaan terminal yang bersih. Kami dengan sengaja tidak mencoba menjaga saluran tetap konsisten secara internal selama loop โ itu berarti jalur rollback yang sendiri harus sesuai dengan anggaran 15 menit. Pembersihan adalah satu sapuan, bukan transaksi.
5. Jangan memperbesar Lambda; gantikan ketika katalog melakukannya. Untuk semua yang kami terapkan hari ini, jalur pemanggilan tunggal selesai jauh di dalam anggaran. Skala keluar yang jujur adalah Step Functions chunking โ membagi daftar putar, menjalankan potongan sebagai mesin negara paralel, merakit kembali. Itulah jalur untuk daftar putar >1 bulan dan 6 bulan. Itu dirancang, tidak diterapkan. Menyebutnya sebagai langkah berikutnya lebih berguna daripada berpura-pura itu sudah berjalan.
Hasil
- Dalam pengujian internal, penerapan 195 program selesai dalam ~44 detik โ turun dari baseline multi-menit, satu program pada satu waktu.
- Target terdokumentasi untuk daftar putar 360 program (~1 bulan) adalah โค90 detik, nyaman di dalam batas waktu backend 615 detik dan batas 15 menit Lambda.
- Satu program buruk dalam batch tidak lagi membatalkan 24 lainnya. Operator mendapatkan peta status per-program kembali dari setiap penerapan.
- Bagian lambat dari permintaan โ pencarian Mongo dan ffprobe โ dibayar sekali per sumber daya unik, bukan sekali per entri jadwal.
- Batas 15 menit berhenti menjadi faktor pembatas untuk ukuran katalog yang sebenarnya kami kirimkan. Ketika itu menjadi satu lagi, Step Functions chunking adalah jawabannya, bukan Lambda yang lebih besar.
Tumpukan Teknologi: AWS Lambda ยท AWS MediaLive ยท NestJS ยท MongoDB ยท Node 18 ยท ffprobe ยท TypeScript ยท AWS SDK v3

