Konteks dan cakupan
Rancang distributed job scheduler multi-tenant. Sistem ini mendukung tugas satu kali dan tugas cron dengan zona waktu IANA, menyimpan 20 juta jadwal aktif, membuat 200 juta kemunculan per hari, dan dapat memiliki 500.000 pemicu pada awal setiap jam. Di bawah beban puncak normal, tugas-tugas ketat harus mencapai antrean durable dalam waktu 5 detik dari waktu yang dijadwalkan pada p99. Tugas-tugas yang tidak memerlukan waktu persis dapat disebarkan dalam jendela fleksibel 5 menit.
API mendukung pembuatan, menjeda, melanjutkan, memperbarui, dan membatalkan jadwal. Pengiriman bersifat at-least-once. Penjadwal bertanggung jawab untuk mengubah waktu yang dijadwalkan menjadi sebuah kemunculan dan menempatkannya pada antrean target. Penempatan kontainer, dependensi DAG, dan orkestrasi alur kerja arbitrer berada di luar cakupan. Waktu penyelesaian tugas sebenarnya bukan bagian dari SLO penjadwalan 5 detik.
Pertanyaan ini cocok untuk peran backend, platform, infrastruktur, dan perancangan sistem tingkat menengah hingga senior. Materi desain sistem publik tahun 2026 masih memperlakukan job scheduler sebagai masalah wawancara yang berdiri sendiri, sementara dokumentasi AWS dan Kubernetes saat ini mengungkap batasan praktis seputar jendela fleksibel, pembuatan duplikat atau yang hilang, misfire, zona waktu, dan percobaan ulang (retries). Tantangan utamanya bukan mem-parsing cron, melainkan mewujudkan (materializing) satu waktu yang dijadwalkan secara andal ke dalam eksekusi yang dapat dilacak, dapat dicoba ulang, dan idempoten.
Hal yang dievaluasi oleh pewawancara
Sinyal pertama adalah memisahkan Schedule, Occurrence, dan Attempt. Jadwal (schedule) mendeskripsikan waktu di masa mendatang. Kemunculan (occurrence) merepresentasikan satu waktu terjadwal yang spesifik. Percobaan (attempt) merepresentasikan satu upaya pengiriman atau pemrosesan untuk kemunculan tersebut. Satu baris tunggal dengan next_run_at dan status mencampuradukkan percobaan ulang, riwayat, pembaruan, dan pemicu berikutnya.
Sinyal kedua adalah menolak untuk menjanjikan exactly-once secara sembarangan. Penjadwal dapat mengalami crash setelah memasukkan ke antrean tetapi sebelum mencatat keberhasilan, dan worker dapat menyelesaikan efek samping sebelum kehilangan pengakuan (acknowledgment)-nya. Kubernetes secara eksplisit mencatat bahwa CronJob terkadang dapat membuat dua Jobs atau tidak ada Job sama sekali dan oleh karena itu merekomendasikan job yang idempoten. Visibility lease pada antrean standar juga tidak dapat sepenuhnya mencegah pengiriman duplikat. Jawaban yang kuat memilih pengiriman at-least-once dan membuat efek bisnis menjadi idempoten dengan ID kemunculan yang stabil.
Sinyal ketiga adalah menangani lonjakan tersinkronisasi. Rata-rata harian hanya sekitar 2.315 kemunculan per detik, tetapi menempatkan 500.000 pemicu ketat pada antrean dalam waktu 5 detik memerlukan sekitar 100.000 pengiriman per detik. Kapasitas yang didasarkan pada rata-rata akan gagal pada awal jam. Satu heap global terurut waktu juga menciptakan titik panas (hot spot) kapasitas dan ketersediaan.
Terakhir, perilaku waktu dan kegagalan harus menjadi kontrak produk: apakah cron berarti waktu jam dinding lokal atau interval tetap, apa yang terjadi pada waktu daylight-saving yang tidak ada atau berulang, apakah pemadaman sepuluh menit menyebabkan pengejaran (catch-up) atau dilewati (skip), apakah eksekusi boleh tumpang tindih, dan apa arti pembaruan atau pembatalan setelah suatu kemunculan masuk antrean.
Pertanyaan klarifikasi
- Apa yang diukur oleh lima detik? Definisikan ini sebagai
enqueued_at - scheduled_for, yang hanya mencakup penjadwalan dan proses memasukkan ke antrean (enqueueing). Jika penyelesaian tugas juga diwajibkan, model kapasitas akan berubah total. - Apakah jadwal satu kali, cron, dan fixed-rate semuanya diperlukan? Desain ini mendukung jadwal satu kali dan cron. Setiap 24 jam berbeda dengan pukul 09:00 waktu lokal saat melewati perubahan daylight-saving dan tidak boleh menggunakan perhitungan yang sama.
- Apakah duplikasi lebih baik daripada kelalaian (omission)? Desain ini memilih pengiriman at-least-once dan menangani duplikasi dengan idempotensi. Efek eksternal yang tidak dapat diulang membutuhkan idempotency key atau risiko residual yang eksplisit.
- Apa yang terjadi pada kemunculan yang terlewat selama downtime? Setiap jadwal membutuhkan
misfire_policy, keterlambatan maksimum, dan batas catch-up. Jika tidak, pemulihan dapat tiba-tiba membuat jutaan kemunculan usang. - Bolehkah satu jadwal tumpang tindih dengan dirinya sendiri? Standarnya adalah
ALLOW, denganSKIP_IF_RUNNINGsebagai opsi lain. Mengganti pekerjaan in-flight yang sedang berjalan tidak aman jika efek sampingnya tidak dapat dibatalkan. - Seberapa kuat jaminan pembaruan dan pembatalan? Kemunculan yang tertunda dari versi lama harus menjadi tidak valid. Menghapus jadwal tidak dapat menarik kembali pekerjaan yang telah diklaim atau diselesaikan oleh worker, sehingga API harus melaporkan status sebenarnya.
- Apa targetnya? Desain ini menempatkan kemunculan pada antrean durable untuk handler yang terdaftar. Kode pengguna arbitrer dikecualikan agar sandboxing dan penempatan komputasi tidak mengaburkan masalah penjadwalan.
- Isolasi tenant apa yang diperlukan? Terapkan kuota terpisah untuk jumlah jadwal, laju pemicu, konkurensi yang berjalan, dan laju catch-up. Satu batch awal jam tidak boleh menghabiskan seluruh shard dan antrean.
Jawaban 30 detik
“Saya akan memisahkan jadwal, kemunculan, dan percobaan. Jadwal menyimpan ekspresi, zona waktu IANA, versi, dan pemicu berikutnya. Node penjadwal melakukan sharding berdasarkan bucket waktu dan hash ID jadwal serta hanya mematerialisasi horizon yang terbatas. ID kemunculan diturunkan dari ID jadwal, versi, dan waktu terjadwal asli; constraint unik mencegah materialisasi duplikat selama failover. Kemunculan, pemicu berikutnya, dan outbox di-commit dalam satu transaksi, lalu relay menulis ke antrean durable secara at-least-once. Worker memproses di bawah visibility lease yang dapat diperpanjang, sementara handler bisnis melakukan deduplikasi berdasarkan ID kemunculan. Tugas-tugas ketat dipersiapkan untuk kapasitas beban puncak, dan tugas-tugas fleksibel menggunakan jitter deterministik. Perilaku misfire, tumpang tindih, zona waktu, dan pembatalan merupakan kebijakan eksplisit. Saya akan memvalidasinya dengan 500.000 pemicu serentak, crash pada setiap titik serah terima, batas daylight-saving, dan race condition pembatalan.”
Pembahasan mendalam langkah demi langkah
Hitung data plane sebelum menggambar komponen:
average = 200,000,000 / 86,400 ≈ 2,315 occurrences/s
strict_peak = 500,000 / 5 = 100,000 dispatches/sPuncak ketat lebih dari 43 kali lipat dari rata-rata harian. Jika jadwal aktif dan sebuah kemunculan masing-masing menggunakan sekitar 1 KB penyimpanan logis, metadata jadwal kira-kira 20 GB dan kemunculan menambah sekitar 200 GB per hari. Indeks, replika, pesan antrean, dan retensi riwayat akan menambah kapasitas lebih banyak. Ini adalah asumsi ukuran untuk partisi dan tingkatan penyimpanan; kolom dan indeks sebenarnya harus diuji beban (load-tested).
Control plane memvalidasi ekspresi, mengotorisasi tenant, menegakkan kuota, membuat secara idempoten, dan memberi versi pada pembaruan. Model yang disederhanakan adalah:
Schedule(schedule_id, tenant_id, expression, time_zone, version,
next_run_at, state, misfire_policy, max_lateness,
overlap_policy, flexible_window)
Occurrence(occurrence_id, schedule_id, schedule_version,
scheduled_for, available_at, state, attempt_count)
Attempt(attempt_id, occurrence_id, lease_token, started_at,
finished_at, result)
UNIQUE(schedule_id, schedule_version, scheduled_for)API pembuatan menerima idempotency key dari pemanggil. API ini memvalidasi ekspresi cron dan zona waktu serta mempratinjau beberapa pemicu mendatang sehingga ekspresi yang valid secara sintaksis tetapi tidak diinginkan dapat terdeteksi lebih awal. Simpan next_run_at dalam UTC sambil mempertahankan ekspresi asli dan zona IANA. Tugas harian waktu lokal harus mendapatkan waktu berikutnya dari aturan zona alih-alih menambahkan 24 jam ke timestamp UTC sebelumnya.
Kasus batas zona waktu memerlukan kontrak yang stabil. Desain ini melewati waktu lokal yang tidak ada saat spring-forward dan berjalan sekali ketika fall-back mengulang waktu jam dinding. Pembaruan zona waktu hanya memengaruhi kemunculan di masa mendatang di bawah versi jadwal yang baru. AWS Scheduler mendokumentasikan perilaku lewati-dan-jalankan-sekali yang sama, tetapi di sini hal tersebut tetap merupakan pilihan produk dan bukan aturan penjadwal universal. Tipe fixed-rate di masa mendatang akan menggunakan durasi yang telah berlalu dan tidak akan bergeser dengan daylight saving.
Penyimpanan jadwal memiliki indeks yang setara dengan (time_bucket, shard, next_run_at), dengan shard = hash(schedule_id) mod N. Node penjadwal menyewa (lease) beberapa shard logis dan memindai horizon perencanaan yang terbatas, seperti beberapa menit ke depan. Leader global tunggal membatasi kapasitas dan pemulihan. Sewa shard mengurangi pemindaian duplikat, sementara keunikan database dan penulisan bersyarat (conditional writes) menyediakan batas kebenaran akhir.
Untuk setiap jadwal yang jatuh tempo, satu transaksi menyisipkan Occurrence deterministik, memajukan next_run_at secara kondisional dari versi jadwal saat ini, dan menulis baris outbox pengiriman dengan available_at. Jika dua node tumpang tindih selama transisi sewa, batasan keunikan hanya menyisakan satu kemunculan (schedule_id, version, scheduled_for). Pembaruan kondisional mencegah node lama memundurkan pemicu berikutnya ke belakang.
Jangan membuat riwayat cron tak terbatas di muka. Horizon perencanaan yang terlalu pendek meneruskan variasi latensi penyimpanan (storage jitter) langsung ke dalam SLO 5 detik. Horizon yang terlalu panjang membuat pembaruan dan pembatalan harus membatalkan sejumlah besar kemunculan versi lama. Pilih horizon yang mencakup failover penjadwal dan anggaran waktu enqueue, lalu sesuaikan berdasarkan lag yang terukur. Jadwal satu kali menjadi terminal; jadwal berulang hanya menyimpan kursor pemicu berikutnya sementara kemunculan lama dipindahkan ke riwayat berjenjang.
Mendekati available_at, dispatch relay menulis event outbox ke antrean durable yang dipartisi berdasarkan tenant dan prioritas. Jika relay mengalami crash setelah antrean menerima pesan tetapi sebelum ada acknowledgment dari database, relay akan mengirimkan occurrence_id yang sama lagi. Duplikasi tersebut disengaja. Menandai terkirim sebelum masuk antrean dapat menghilangkan pekerjaan, sementara memasukkan ke antrean sebelum menandai dapat menduplikasinya. Outbox transaksional menjadikan kompromi ini sebagai jalur at-least-once yang eksplisit dan dapat dicoba ulang secara idempoten.
Lima ratus ribu tugas awal jam membutuhkan lebih dari sekadar thread polling ekstra. Bagi setiap bucket waktu ke dalam shard hash ID jadwal yang cukup. Jika uji beban menunjukkan bahwa satu shard dapat melakukan pengiriman Q per detik dengan aman menggunakan transaksi nyata, indeks, dan penulisan antrean, maka jalur ketat membutuhkan setidaknya ceil(100,000 / Q) shard yang tersedia secara simultan ditambah ruang cadangan untuk kegagalan (failure headroom). Antrean menerapkan keadilan berbobot tenant (tenant-weighted fairness) dan kuota laju sehingga satu tenant tidak dapat menghabiskan jalur ketat.
Tugas dengan jendela 5 menit menggunakan jitter deterministik: available_at = scheduled_for + hash(occurrence_id) mod 300s. Kemunculan yang sama mendapatkan waktu yang sama setelah percobaan ulang dan failover, membuat perilaku dapat direproduksi sambil menyebarkan pemicu yang berkorelasi. Tugas ketat mempertahankan waktu asli dan kapasitas yang dicadangkan. Builders' Library milik Amazon juga mengidentifikasi jitter pada tugas housekeeping berkala sebagai cara untuk mengurangi kegagalan yang berkorelasi.
Worker menerima kemunculan di bawah visibility lease dengan batas waktu dan memperbaruinya dengan heartbeat untuk pekerjaan yang panjang. Berakhirnya masa sewa membuat pesan terlihat kembali, dan pengiriman duplikat tidak dapat dihindari bahkan selama jendela tersebut. Oleh karena itu, state machine tidak dapat memperlakukan lease sebagai exactly-once:
SCHEDULED -> ENQUEUED -> RUNNING -> SUCCEEDED
| |
| +-> RETRY_WAIT -> ENQUEUED
+------> DEAD
Side states: MISSED, CANCELED, SKIPPED_OVERLAPSetiap klaim mendapatkan lease_token baru atau generasi percobaan yang terus meningkat. Pembaruan penyelesaian harus cocok dengan token saat ini sehingga worker yang mengalami timed-out tidak dapat menimpa status percobaan yang lebih baru. Fencing ini melindungi status penjadwal, bukan efek eksternal yang telah dilakukan oleh worker lama. Idempotensi bisnis menggunakan occurrence_id sebagai unique key dalam transaksi yang sama dengan efek tersebut, atau sebagai idempotency key untuk API hilir. Jika target eksternal tidak memiliki idempotensi dan tidak dapat di-query, risiko duplikasi tetap ada.
Lakukan percobaan ulang berdasarkan kelas kesalahan. Kesalahan parameter permanen masuk ke DEAD. Kegagalan jaringan, throttling, dan respons 5xx sementara menggunakan exponential backoff dengan full jitter, yang dibatasi oleh batas percobaan maksimum, deadline kemunculan, dan anggaran tenant. Antrean DLQ menampung kemunculan yang telah kehabisan jatah percobaan. Pemutaran ulang manual mempertahankan occurrence_id yang sama; menetapkan ID baru akan melewati deduplikasi.
Pemulihan control-plane membutuhkan kebijakan misfire yang eksplisit. SKIP menandai kemunculan yang melewati keterlambatan maksimum sebagai MISSED. FIRE_ONCE hanya memancarkan kemunculan terlewat yang paling baru. CATCH_UP memancarkan paling banyak K, sesuai dengan batas laju catch-up tenant. Batas starting deadline dan missed-schedule pada Kubernetes menunjukkan keputusan yang sama: pemulihan tanpa batas dapat menghilangkan pekerjaan yang diperlukan atau menciptakan recovery storm.
SKIP_IF_RUNNING secara atomik memeriksa keberadaan kemunculan RUNNING saat ini dari jadwal yang sama sebelum menandai yang baru sebagai SKIPPED_OVERLAP. Tanpa transisi status atomik, dua kemunculan dapat sama-sama mengamati tidak adanya pendahulu. Pembatalan atau pembaruan akan menaikkan versi jadwal dan membatalkan kemunculan versi lama yang belum diklaim. Worker memeriksa ulang versi dan penanda pembatalan sebelum menjalankan efek samping. Pekerjaan yang sudah dimulai memerlukan cooperative cancellation, dan efek eksternal yang sudah selesai tidak dapat di-rollback oleh penjadwal.
Observabilitas mengikuti jaminan yang diberikan: p50/p95/p99 untuk schedule_lag = enqueued_at - scheduled_for; baris yang tertunda per bucket waktu; lag materialisasi; konflik keunikan; backlog outbox; usia antrean; klaim duplikat; percobaan ulang dan DLQ; MISSED dan skip karena tumpang tindih; throttling tenant; offset jam; serta waktu yang dihabiskan pada setiap status kemunculan. Ketersediaan API tidak membuktikan bahwa kemunculan yang diharapkan telah mencapai antrean tepat waktu.
Pengujian penerimaan (acceptance testing) pertama-tama menginjeksikan 500.000 kemunculan ketat pada awal jam dan memeriksa p99 5 detik serta keadilan tenant. Kemudian lakukan crash pada penjadwal sebelum penyisipan, setelah commit transaksi, dan setelah pengiriman antrean; pastikan tidak ada kelalaian tersembunyi (silent omission) dan deduplikasi berhasil dilakukan berdasarkan ID kemunculan yang sama. Uji juga skenario worker kehilangan acknowledgment setelah efeknya berjalan, berakhirnya masa sewa, ketiga kebijakan misfire setelah pemadaman control-plane selama sepuluh menit, kedua transisi daylight-saving, race condition pembaruan dan pembatalan, tumpang tindih eksekusi yang lama, serta lonjakan catch-up dari satu tenant.
Contoh jawaban yang kuat
“Saya akan mendefinisikan SLO sebagai waktu terjadwal hingga penerimaan antrean durable, tidak termasuk waktu eksekusi. Dua ratus juta pemicu harian menghasilkan rata-rata sekitar 2.315 per detik, tetapi 500.000 pemicu awal jam dalam lima detik memerlukan jalur ketat yang dirancang untuk kapasitas 100.000 per detik. Pekerjaan fleksibel dapat disebarkan secara deterministik selama lima menit.
Model ini memisahkan jadwal, kemunculan, dan percobaan. Jadwal menyimpan ekspresi cron, zona IANA, versi, dan next_run_at. ID kemunculan diturunkan dari ID jadwal, versi, dan scheduled_for serta memiliki constraint unik. Node penjadwal melakukan sharding berdasarkan bucket waktu dan hash ID jadwal serta menyewa shard untuk pemindaian. Sebuah transaksi menyisipkan kemunculan, memajukan pemicu berikutnya, dan menulis outbox pengiriman, sehingga failover tidak menghilangkan pekerjaan secara diam-diam dan relay yang berulang hanya mengirimkan ID kemunculan yang sama.
Antrean dan worker menggunakan semantik at-least-once. Worker memiliki visibility lease yang dapat diperpanjang, dan penyelesaian harus cocok dengan token sewa saat ini. Handler bisnis menggunakan ID kemunculan sebagai unique key database atau idempotency key hilir. Berakhirnya masa sewa kemudian dapat menambah percobaan tanpa menambah efek bisnis; target eksternal tanpa idempotensi tetap memiliki risiko duplikasi yang eksplisit.
Perilaku misfire, tumpang tindih, zona waktu, dan pembatalan merupakan kebijakan API. Setelah downtime, jadwal dapat dilewati, dipicu sekali, atau mengejar ketertinggalan paling banyak K kali. Waktu cron yang tidak ada akan dilewati dan waktu jam dinding yang berulang akan dijalankan sekali. Pembaruan menaikkan versi, dan worker memeriksa ulang sebelum menjalankan efek samping. Saya akan menguji puncak awal jam, setiap jendela crash, pesan duplikat, batas daylight-saving, dan race condition pembatalan, sambil memantau lag jadwal, backlog yang jatuh tempo, klaim duplikat, kemunculan yang terlewat, DLQ, dan throttling tenant.”
Kesalahan umum
- Menggabungkan jadwal, kemunculan, dan percobaan dalam satu baris → Percobaan ulang menimpa riwayat dan pembaruan tidak dapat mengidentifikasi kemunculan lama → Pisahkan
Schedule,Occurrence, danAttempt. - Merancang kapasitas hanya untuk rata-rata harian 2.315 per detik → Lima ratus ribu pemicu awal jam menyebabkan lag parah → Lakukan uji beban shard pada beban puncak ketat dan sebarkan pekerjaan fleksibel secara deterministik.
- Menggunakan satu leader global dengan min-heap in-memory → Leader menjadi hambatan kapasitas dan pemulihan, dan restart harus membangun ulang semua pekerjaan masa depan → Gunakan indeks waktu durable, shard logis, dan horizon terbatas.
- Menandai terkirim sebelum menulis ke antrean → Kegagalan antrean secara diam-diam menghilangkan sebuah kemunculan → Tulis outbox secara transaksional dan lakukan relay secara at-least-once.
- Mengklaim bahwa lock dan visibility timeout menjamin exactly-once → Timeout dan acknowledgment yang hilang tetap menyebabkan percobaan yang tumpang tindih → Gabungkan ID kemunculan yang stabil, fencing token, dan idempotensi bisnis.
- Memutar ulang setiap kemunculan historis yang terlewat setelah pemulihan → Jutaan tugas usang menciptakan pemadaman kedua → Tetapkan keterlambatan maksimum, batas catch-up, dan laju tenant.
- Menambahkan 24 jam dalam UTC untuk cron harian lokal → Waktu jam dinding bergeser saat daylight saving → Pertahankan zona IANA dan hitung kemunculan lokal berikutnya.
- Menghapus baris untuk menjeda atau membatalkan → Pekerjaan yang telah dimaterialisasi atau diantrekan mungkin masih berjalan, dan riwayat audit hilang → Batalkan berdasarkan versi dan periksa ulang status sebelum efek samping dijalankan.
- Menempatkan setiap tenant pada satu antrean FIFO yang sama → Batch besar di awal jam memblokir tenant lain → Gunakan penjadwalan adil yang sadar-tenant serta pisahkan kuota pemicu dan konkurensi.
- Hanya memantau keberhasilan API → Jadwal dapat berhasil dibuat tetapi tidak pernah terpicu tepat waktu → Lacak lag jadwal, backlog yang jatuh tempo, kemunculan yang terlewat, dan rekonsiliasi status.
Tindak lanjut
Tindak lanjut 1: Bagaimana jika penjadwal mengalami crash setelah mengirim ke antrean tetapi sebelum memperbarui outbox?
Relay mengirimkan occurrence_id yang sama lagi. Konsumen antrean dan target bisnis melakukan deduplikasi pada ID tersebut, dan acknowledgment outbox bersifat kondisional. Duplikasi dipilih daripada kehilangan data karena database dan antrean tidak berbagi satu transaksi yang sama. Log transaksional dapat mempersempit jendela masalah, tetapi efek eksternal tetap memerlukan idempotensi.
Tindak lanjut 2: Bagaimana Anda mendukung wilayah active-active?
Tetapkan satu home region dan generasi yang terus meningkat untuk setiap jadwal. Hanya wilayah yang memegang generasi saat ini yang boleh mematerialisasi kemunculan, sementara antrean eksekusi dapat merutekan ke wilayah target. Failover menaikkan generasi sebelum wilayah baru melanjutkan proses dari kursor durable. Kunci kemunculan yang unik secara global atau lapisan agregasi tetap menjadi batas akhir pencegahan duplikat. Control plane single-writer dengan failover regional lebih sederhana ketika penulisan lintas wilayah tidak diperlukan.
Tindak lanjut 3: Pada saat fall-back, waktu lokal 01:30 terjadi dua kali. Berapa kali eksekusi harus berjalan?
Tidak ada jawaban universal; ini adalah bagian dari kontrak jadwal. Desain ini berjalan sekali dengan menggabungkan dua kandidat UTC menggunakan tanggal lokal, waktu jam dinding, dan zona waktu. Rekonsiliasi keuangan yang memerlukan kedua waktu fisik tersebut akan memilih dua kemunculan dengan nilai scheduled_for yang berbeda. API harus mempratinjau jadwal eksekusi mendatang sebelum menyimpan.
Tindak lanjut 4: Sebuah tugas berjalan selama dua jam tetapi berulang setiap jam. Apa yang terjadi?
ALLOW menjalankannya secara konkuren. SKIP_IF_RUNNING secara atomik menandai kemunculan baru sebagai SKIPPED_OVERLAP. Jika produk mengharuskan menunggu, tambahkan QUEUE_ONE dan pertahankan paling banyak satu kemunculan yang tertunda. Mengganti tugas lama hanya aman jika handler mendukung cooperative cancellation karena efek samping mungkin sudah terjadi.
Tindak lanjut 5: Penjadwal mati selama sehari. Bagaimana Anda memulihkannya tanpa membebani target?
Terapkan SKIP, FIRE_ONCE, atau CATCH_UP terbatas per jadwal, lalu batasi laju berdasarkan kapasitas tenant dan target. Lanjutkan pemindaian dari next_run_at yang durable alih-alih mengganti kursor dengan waktu saat ini. Lacak waktu tertunda tertua dan estimasi durasi pengurasan (drain), serta pisahkan pekerjaan baru yang ketat dari kapasitas catch-up.
Tindak lanjut 6: Bagaimana Anda membuktikan tidak ada kemunculan yang terlewat secara diam-diam?
Rekonsiliator offline secara independen menghitung ulang set kemunculan yang diharapkan dari versi jadwal dan aturan waktu, lalu membandingkannya dengan set unique key Occurrence. Setiap item yang diharapkan harus berstatus succeeded, failed, canceled, missed, atau absent. Metrik online mendeteksi lag; rekonsiliasi mendeteksi celah di mana sistem tidak melaporkan kesalahan karena suatu kemunculan memang tidak pernah dibuat.