Membangun untuk sistem besar dan pekerjaan latar belakang yang berjalan lama.Kredit: Ilias Chebbi di Unsplash Beberapa bulan yang lalu, saya mengambil peran yang mengharuskan membangun infrastMembangun untuk sistem besar dan pekerjaan latar belakang yang berjalan lama.Kredit: Ilias Chebbi di Unsplash Beberapa bulan yang lalu, saya mengambil peran yang mengharuskan membangun infrast

Membangun Spotify untuk Khotbah.

2025/12/11 21:15

Membangun untuk sistem besar dan pekerjaan latar belakang yang berjalan lama.

Kredit: Ilias Chebbi di Unsplash

Beberapa bulan yang lalu, saya mengambil peran yang mengharuskan membangun infrastruktur untuk streaming media (audio). Tetapi di luar menyajikan audio sebagai potongan yang dapat dialirkan, ada pekerjaan pemrosesan media yang berjalan lama dan pipeline RAG yang ekstensif yang melayani transkripsi, transcoding, embedding, dan pembaruan media sekuensial. Membangun MVP dengan pola pikir produksi membuat kami mengulangi hingga kami mencapai sistem yang mulus. Pendekatan kami adalah pendekatan di mana kami mengintegrasikan fitur dan tumpukan prioritas yang mendasarinya.

Perhatian Utama:

Selama proses pembangunan, setiap iterasi datang sebagai respons terhadap kebutuhan langsung dan sering "mencakup" keseluruhan. Perhatian awal adalah antrian pekerjaan, yang cukup dengan Redis; kami hanya menembak dan melupakan. Bull MQ dalam framework NEST JS memberi kami kontrol yang lebih baik atas percobaan ulang, backlog, dan antrian dead-letter. Secara lokal dan dengan beberapa payload dalam produksi, kami mendapatkan aliran media yang benar. Kami segera dibebani oleh beban Observabilitas:
Log → Catatan pekerjaan (permintaan, respons, kesalahan).
Metrik → Berapa banyak / seberapa sering pekerjaan ini berjalan, gagal, selesai, dll.
Jejak → Jalur yang diambil pekerjaan melintasi layanan (fungsi/metode yang dipanggil dalam jalur aliran).

Anda dapat menyelesaikan beberapa hal ini dengan merancang API dan membangun dasbor kustom untuk menghubungkannya, tetapi masalah skalabilitas akan cukup. Dan faktanya, kami memang merancang API tersebut.

Membangun untuk Observabilitas

Tantangan mengelola alur kerja backend yang kompleks dan berjalan lama, di mana kegagalan harus dapat dipulihkan, dan status harus tahan lama, Inngest menjadi penyelamat arsitektur kami. Ini secara fundamental membingkai ulang pendekatan kami: setiap pekerjaan latar belakang yang berjalan lama menjadi fungsi latar belakang, dipicu oleh peristiwa tertentu.

Misalnya, peristiwa event Transcription.request akan memicu fungsi TranscribeAudio. Fungsi ini mungkin berisi step-run untuk: fetch_audio_metadata, deepgram_transcribe, parse_save_trasncription, dan notify_user.

Mendekonstruksi Alur Kerja: Fungsi Inngest dan Step-run

Primitif ketahanan inti adalah step-run. Fungsi latar belakang secara internal dipecah menjadi step-run ini, masing-masing berisi blok logika minimal dan atomik.

  • Logika Atomik: Fungsi mengeksekusi logika bisnis Anda langkah demi langkah. Jika suatu langkah gagal, status seluruh run dipertahankan, dan run dapat dicoba lagi. Ini memulai ulang fungsi dari awal. Langkah-langkah individual atau step-run tidak dapat dicoba ulang secara terisolasi.
  • Serialisasi Respons: Step-run didefinisikan oleh responsnya. Respons ini secara otomatis diserialisasi, yang penting untuk mempertahankan struktur data kompleks atau yang diketik secara kuat melintasi batas eksekusi. Step-run berikutnya dapat mengurai respons yang diserialisasi ini dengan andal, atau logika dapat digabungkan menjadi satu langkah untuk efisiensi.
  • Decoupling dan Penjadwalan: Dalam sebuah fungsi, kita dapat secara kondisional mengantri atau menjadwalkan peristiwa baru yang bergantung, memungkinkan pola fan-out/fan-in yang kompleks dan penjadwalan jangka panjang hingga satu tahun. Kesalahan dan keberhasilan pada titik mana pun dapat ditangkap, dicabangkan, dan ditangani lebih lanjut dalam alur kerja.

Abstrak fungsi Inngest:

import { inngest } from 'inngest-client';

export const createMyFunction = (dependencies) => {
return inngest.createFunction(
{
id: 'my-function',
name: 'My Example Function',
retries: 3, // retry the entire run on failure
concurrency: { limit: 5 },
onFailure: async ({ event, error, step }) => {
// handle errors here
await step.run('handle-error', async () => {
console.error('Error processing event:', error);
});
},
},
{ event: 'my/event.triggered' },
async ({ event, step }) => {
const { payload } = event.data;

// Step 1: Define first step
const step1Result = await step.run('step-1', async () => {
// logic for step 1
return `Processed ${payload}`;
});

// Step 2: Define second step
const step2Result = await step.run('step-2', async () => {
// logic for step 2
return step1Result + ' -> step 2';
});

// Step N: Continue as needed
await step.run('final-step', async () => {
// finalization logic
console.log('Finished processing:', step2Result);
});

return { success: true };
},
);
};

Model berbasis peristiwa dari Inngest memberikan wawasan terperinci ke dalam setiap eksekusi alur kerja:

  • Pelacakan Peristiwa Komprehensif: Setiap eksekusi fungsi yang diantrekan dicatat terhadap peristiwa asalnya. Ini memberikan jejak tingkat tinggi yang jelas dari semua aktivitas yang terkait dengan tindakan pengguna tunggal.
  • Wawasan Run Terperinci: Untuk setiap eksekusi fungsi (baik keberhasilan maupun kegagalan), Inngest menyediakan log terperinci melalui pelaporan ack (acknowledge) dan nack (negative acknowledgment). Log ini mencakup jejak tumpukan kesalahan, payload permintaan lengkap, dan payload respons yang diserialisasi untuk setiap step-run individual.
  • Metrik Operasional: Di luar log, kami mendapatkan metrik penting tentang kesehatan fungsi, termasuk tingkat keberhasilan, tingkat kegagalan, dan jumlah percobaan ulang, memungkinkan kami untuk terus memantau keandalan dan latensi alur kerja terdistribusi kami.

Membangun untuk Ketahanan

Peringatan untuk mengandalkan pemrosesan peristiwa murni adalah bahwa sementara Inngest secara efisien mengantrekan eksekusi fungsi, peristiwa itu sendiri tidak diantrekan secara internal dalam arti broker pesan tradisional. Tidak adanya antrian peristiwa eksplisit ini dapat menjadi masalah dalam skenario lalu lintas tinggi karena potensi kondisi balapan atau peristiwa yang hilang jika titik akhir ingesti kewalahan.

Untuk mengatasi ini dan menegakkan ketahanan peristiwa yang ketat, kami menerapkan sistem antrian khusus sebagai buffer.

AWS Simple Queue System (SQS) adalah sistem pilihan (meskipun sistem antrian yang kuat lainnya juga bisa dilakukan), mengingat infrastruktur kami yang ada di AWS. Kami merancang sistem dua antrian: Antrian Utama dan Antrian Surat Mati (DLQ).

Kami membuat Lingkungan Pekerja Elastic Beanstalk (EB) yang secara khusus dikonfigurasi untuk mengkonsumsi pesan langsung dari Antrian Utama. Jika pesan di Antrian Utama gagal diproses oleh Pekerja EB sejumlah kali tertentu, Antrian Utama secara otomatis memindahkan pesan yang gagal ke DLQ khusus. Ini memastikan tidak ada peristiwa yang hilang secara permanen jika gagal dipicu atau diambil oleh Inngest. Lingkungan pekerja ini berbeda dari lingkungan server web EB standar, karena tanggung jawab utamanya adalah konsumsi dan pemrosesan pesan (dalam hal ini, meneruskan pesan yang dikonsumsi ke titik akhir API Inngest).

MEMAHAMI BATAS DAN SPESIFIKASI

Bagian yang kurang diungkapkan dan agak relevan dari membangun infrastruktur skala perusahaan adalah bahwa ia mengkonsumsi sumber daya, dan mereka berjalan lama. Arsitektur microservices menyediakan skalabilitas per layanan. Penyimpanan, RAM, dan batas waktu sumber daya akan berperan. Spesifikasi kami untuk jenis instans AWS, misalnya, bergerak cepat dari t3.micro ke t3.small, dan sekarang dipatok pada t3.medium. Untuk pekerjaan latar belakang yang berjalan lama dan intensif CPU, penskalaan horizontal dengan instans kecil gagal karena kemacetan adalah waktu yang diperlukan untuk memproses satu pekerjaan, bukan volume pekerjaan baru yang memasuki antrian.

Jobs atau functions seperti transcoding, embedding biasanya CPU-bound dan Memory-bound. CPU-bound karena mereka memerlukan penggunaan CPU yang intens dan berkelanjutan, dan Memory-Bound karena mereka sering memerlukan RAM yang substansial untuk memuat model besar atau menangani file atau payload besar secara efisien.

Pada akhirnya, arsitektur yang ditingkatkan ini, menempatkan ketahanan SQS dan eksekusi terkontrol dari lingkungan Pekerja EB langsung di hulu API Inngest, memberikan ketahanan penting. Kami mencapai kepemilikan peristiwa yang ketat, menghilangkan kondisi balapan selama lonjakan lalu lintas, dan mendapatkan mekanisme surat mati yang tidak mudah menguap. Kami memanfaatkan Inngest untuk kemampuan orkestrasi alur kerja dan debugging, sambil mengandalkan primitif AWS untuk throughput pesan dan ketahanan maksimum. Sistem yang dihasilkan tidak hanya dapat diskalakan tetapi sangat dapat diaudit, berhasil menerjemahkan pekerjaan backend yang kompleks dan berjalan lama menjadi mikro-langkah yang aman, dapat diamati, dan toleran terhadap kegagalan.


Building Spotify for Sermons. awalnya dipublikasikan di Coinmonks di Medium, di mana orang-orang melanjutkan percakapan dengan menyoroti dan merespons cerita ini.

Penafian: Artikel yang diterbitkan ulang di situs web ini bersumber dari platform publik dan disediakan hanya sebagai informasi. Artikel tersebut belum tentu mencerminkan pandangan MEXC. Seluruh hak cipta tetap dimiliki oleh penulis aslinya. Jika Anda meyakini bahwa ada konten yang melanggar hak pihak ketiga, silakan hubungi [email protected] agar konten tersebut dihapus. MEXC tidak menjamin keakuratan, kelengkapan, atau keaktualan konten dan tidak bertanggung jawab atas tindakan apa pun yang dilakukan berdasarkan informasi yang diberikan. Konten tersebut bukan merupakan saran keuangan, hukum, atau profesional lainnya, juga tidak boleh dianggap sebagai rekomendasi atau dukungan oleh MEXC.