Topik wawancara representatif

Wawancara system design: Merancang workflow engine yang tahan lama (durable) dengan persetujuan manusia

Desain sistemSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Rancang workflow engine untuk proses yang ditentukan pelanggan hingga 20 langkah. Satu langkah memerlukan persetujuan manusia dan dapat menunggu selama berhari-hari; aktivitas dapat gagal, dikirim dua kali, atau berhasil saat responsnya hilang. Sistem harus pulih dari kegagalan dan mendukung timeout, pembatalan, audit, serta pembaruan versi. Jelaskan state model, scheduling, idempotensi, keamanan callback, skala, dan kompromi (trade-off).

Konteks dan arahan

Rancang workflow engine untuk proses yang ditentukan pelanggan hingga 20 langkah. Satu langkah memerlukan persetujuan manusia dan dapat menunggu selama berhari-hari; aktivitas dapat gagal, dikirim dua kali, atau berhasil saat responsnya hilang. Sistem harus pulih dari kegagalan dan mendukung timeout, pembatalan, audit, serta pembaruan versi. Jelaskan state model, scheduling, idempotensi, keamanan callback, skala, dan kompromi (trade-off).

Pertanyaan perancangan sistem ini cocok untuk peran backend, platform, dan infrastruktur. Fokusnya adalah semantik eksekusi yang tahan lama (durable execution semantics), bukan sekadar menggambar antrean sederhana. Batasan 20 langkah dan penantian beberapa hari adalah asumsi wawancara; perjelas throughput, latensi, isolasi tenant, sensitivitas data, target pemulihan, dan kewajiban retensi terlebih dahulu.

Hal yang dinilai oleh pewawancara

Pewawancara mencari pemisahan antara state workflow, eksekusi aktivitas, dan efek samping eksternal; pengakuan eksplisit bahwa aktivitas dapat berjalan setidaknya sekali (at least once); serta kunci idempotensi yang terikat pada invarian bisnis. Persetujuan manusia memerlukan kredensial yang tidak dapat dipalsukan, memiliki batas kedaluwarsa, dan sekali pakai. Jawaban juga harus mendefinisikan riwayat event, snapshot, timer, pembatalan, versi, dan pemulihan operasional.

Pertanyaan klarifikasi awal

  • Berapa konkurensi per tenant, laju mulai workflow, dan waktu tunggu maksimum?
  • Apakah aktivitas berupa fungsi, kontainer, atau layanan HTTP eksternal, dan efek samping mana yang tidak dapat diubah (irreversible)?
  • Bagaimana approver diautentikasi, diotorisasi, dan diganti? Apakah persetujuan kuorum diperlukan?
  • Bisakah percobaan ulang (retry) mengulang suatu aktivitas, dan bisakah layanan bisnis menerima kunci idempotensi?
  • Bagaimana definisi dipublikasikan, dibekukan, dan dimigrasikan? Apakah instans yang sedang berjalan mengikuti versi baru?
  • Field audit apa yang harus disimpan, dan siapa yang boleh membaca atau mengubahnya?
  • Apakah pembatalan, jeda (pause), retry manual, atau skip langkah merupakan operasi produk yang normal?

Kerangka jawaban 30 detik

“Saya akan memodelkan workflow sebagai state machine yang tahan lama: simpan versi definisi, eksekusi (run), percobaan aktivitas, log event, dan snapshot saat ini secara terpisah. Scheduler mengirimkan tugas aktivitas yang dapat dicoba ulang; worker melaporkan hasil dengan ID aktivitas, percobaan, dan kunci idempotensi, lalu state machine melakukan deduplikasi. Persetujuan manusia mendapatkan token sekali pakai berdurasi singkat yang terikat pada run, langkah, tenant, dan versi persetujuan. Timer, timeout, dan pembatalan adalah durable event. Saya akan menskalakannya dengan antrean terpartisi dan kuota tenant, lalu memvalidasi pemulihan dengan replay, audit, dan fault injection.”

Jawaban langkah demi langkah

Tentukan model eksekusi terlebih dahulu. Definisi workflow adalah versi immutable yang berisi tipe langkah, pemetaan input, timeout, kebijakan retry, dan aturan kompensasi. Suatu run mereferensikan satu versi yang dibekukan, sehingga memublikasikan definisi baru tidak akan menulis ulang riwayat secara diam-diam. Bangun kembali state dari log event append-only; gunakan snapshot untuk mempercepat pembacaan. Penambahan event memerlukan kondisi urutan atau versi agar proses penulisan bersamaan (concurrent writers) tidak saling menimpa.

Jangan memanggil layanan eksternal di dalam transaksi database. Lakukan commit pada event ActivityScheduled, biarkan scheduler memasukkan tugas ke dalam antrean, minta worker memperoleh lease dan memanggil layanan, lalu commit ActivitySucceeded, ActivityFailed, atau ActivityTimedOut. Terima hasil hanya untuk run, langkah, dan percobaan yang diharapkan. Hasil yang terlambat atau duplikat adalah bukti audit, bukan transisi state.

Model state minimal adalah:

EntityKey fieldsPurpose
DefinitionVersiontenant, definition, version, digestFreeze steps and policies
WorkflowRunrun, definitionVersion, status, sequenceTrack an instance
Eventrun, sequence, type, payload, createdAtFacts and replay
ActivityAttemptstep, attempt, lease, idempotencyKey, statusDelivery, lease, result
Approvalstep, tokenHash, approver, expiresAt, statusHuman approval credential
Timerrun, step, fireAt, generation, statusWakeups, delays, timeouts

Pengiriman bersifat setidaknya sekali (at-least-once); konfirmasi antrean (ack) bukanlah penyelesaian bisnis. Pesan membawa run ID, step ID, percobaan, versi definisi, dan kunci idempotensi. Lease mencegah dua konsumen bekerja secara bersamaan, sedangkan fencing token atau conditional write menolak worker yang sudah usang. Berakhirnya masa lease memungkinkan pengiriman ulang, tetapi efek eksternal duplikat bergantung pada kontrak aktivitas.

Tangani idempotensi pada beberapa lapisan. Event state machine menggunakan kunci (run, sequence) yang unik. Hasil aktivitas menggunakan (run, step, idempotencyKey). Pembayaran, email, atau penulisan ke layanan bisnis harus menerima kunci yang sama atau menerapkan batasan keunikan bisnis. Jika panggilan berhasil tetapi responsnya hilang, retry harus mengembalikan hasil yang sudah selesai atau duplikat yang aman. Jangan mengklaim tepat sekali (exactly-once) secara menyeluruh (end-to-end). Untuk efek non-idempoten, gunakan peninjauan manusia, kompensasi, atau kebijakan tanpa retry.

URL persetujuan bukanlah otorisasi. Hasilkan materi acak berentropi tinggi, simpan hanya hash-nya, dan ikat token ke tenant, run, langkah, tindakan, dan kedaluwarsa. Pada callback, validasi token, tanda tangan atau identitas login, perlindungan CSRF, status sekali pakai, dan langkah workflow saat ini. Periksa kembali otorisasi approver pada saat pengiriman. Persetujuan dan penolakan menjadi audit event yang tahan manipulasi; callback yang kedaluwarsa tidak valid.

Pertahankan timer secara persisten. Simpan fireAt dan generation saat membuat timeout atau tunggu. Scheduler memindai indeks atau bucket waktu, mengklaim timer yang jatuh tempo dengan pembaruan bersyarat (conditional update), dan mendeduplikasi pengulangan dengan kondisi generation dan state. Restart akan memulihkan data dari penyimpanan. Penyelesaian persetujuan atau pembatalan menandai timer lama sebagai usang; in-memory sleep tidak boleh menahan worker selama berhari-hari.

Pembatalan, jeda, dan perbaikan adalah perintah state machine yang eksplisit. Pembatalan mencatat niat dan mencegah pekerjaan yang belum dimulai; efek eksternal yang sedang berjalan tidak dapat dibatalkan secara ajaib, jadi tunggu hasilnya atau jalankan kompensasi. Skip oleh admin, retry, dan pengeditan input memerlukan otorisasi, alasan, state lama, state baru, dan audit event. Jangan pernah mengedit snapshot secara langsung, atau proses replay akan menghasilkan output yang berbeda.

Isolasi versi per run. Definisi baru mendapatkan digest baru; run yang ada mempertahankan versi lama secara default. Migrasi harus mendefinisikan state dan input yang kompatibel, memperoleh persetujuan yang diperlukan, dan menambahkan event WorkflowMigrated dengan kedua versi. Worker hanya menerima versi definisi yang mereka jalankan, mencegah tugas lama memajukan state machine baru secara tidak benar.

Skalakan dengan mempartisi berdasarkan tenant atau run ID. Berikan kuota konkurensi pada hot tenant dan pisahkan pool worker berdasarkan tipe aktivitas dan prioritas. Tambahkan event ke penyimpanan terpartisi, simpan snapshot dan indeks dalam database online, enkripsi payload sensitif, dan terapkan retensi. Tambahkan backpressure, dead letter, metrik lease, dan rate limit agar satu workflow yang tidak terkendali tidak menghabiskan kapasitas global.

Observabilitas harus melayani operator runtime dan bisnis. Catat langkah saat ini, alasan tunggu, percobaan, penundaan antrean, penundaan timer, waktu tunggu persetujuan, amplifikasi retry, hasil kompensasi, dan versi. Trace dapat membawa pengidentifikasi run, langkah, dan percobaan, sementara input sensitif tetap berada di penyimpanan audit yang terkontrol. Tampilan operasional harus menjelaskan tindakan selanjutnya; "menunggu" bukanlah "gagal."

Lakukan fault injection: crash setelah commit event, pesan duplikat, berakhirnya masa lease, aktivitas berhasil dengan respons hilang, persetujuan yang di-replay, timer duplikat, gangguan database, penumpukan antrean, deployment versi yang terputus, dan kuota tenant habis. Tentukan hasil yang dapat diamati: state lama tidak mengalami regresi, efek samping tidak diulang tanpa kontrak, token tidak dapat digunakan dua kali, dan pemulihan akhirnya berlanjut atau memasuki status penanganan manusia yang eksplisit.

Contoh jawaban berkualitas tinggi

“Saya akan membangun state machine yang tahan lama daripada membiarkan worker mengingat state workflow. Versi definisi bersifat immutable dan setiap run mengunci satu versi; log event adalah sumber kebenaran (source of truth) dan snapshot mempercepat pembacaan. State machine melakukan commit pada scheduling event, antrean mengirimkan setidaknya sekali, dan worker melapor dengan run, langkah, percobaan, dan kunci idempotensi. Hasil duplikat atau usang adalah entri audit, bukan transisi yang tidak valid.

Persetujuan membuat token sekali pakai yang terikat pada tenant, run, langkah, dan tindakan; hanya hash-nya yang disimpan dan memiliki masa kedaluwarsa. Callback memeriksa identitas, izin, CSRF, status token, dan langkah saat ini, lalu secara kondisional menggunakan token tersebut dan menambahkan audit event. Persetujuan, penolakan, timeout, dan pembatalan adalah event, bukan pengeditan snapshot langsung.

Timer mempertahankan fireAt dan generation secara persisten. Scheduler berbasis bucket mengklaimnya dengan conditional write; restart memulihkannya dan pemicuan duplikat dideduplikasi. Lease mencegah worker bersamaan dan fencing token menolak penulisan yang usang. Pembayaran atau email tanpa kontrak idempotensi downstream yang terbukti tidak dapat menjadi exactly-once; gunakan downstream key, batasan keunikan, kompensasi, atau penanganan manusia.

Run tidak secara diam-diam mengikuti definisi baru; migrasi menambahkan event dengan kedua versi. Partisi berdasarkan tenant dan run, isolasi kuota hot tenant, dan gunakan pool worker berdasarkan tipe aktivitas. Terapkan lapisan event append-only, snapshot online, data audit terenkripsi, dan retensi. Fault injection harus mencakup crash, pengiriman ulang, respons hilang, replay callback, timer duplikat, dan deployment versi yang terputus.”

Kesalahan umum

  • Menganggap konfirmasi antrean (ack) sebagai penyelesaian → worker dapat crash setelah efek terjadi dan menerima pesan lagi → deduplikasi dengan durable state dan hasil yang idempoten.
  • Mengklaim exactly-once → transaksi lokal tidak dapat menjamin efek samping terdistribusi → nyatakan pengiriman at-least-once dan idempotensi downstream, kompensasi, atau penanganan manusia.
  • Menganggap URL persetujuan sebagai otorisasi → kebocoran atau replay dapat memberikan akses → ikat identitas, tenant, langkah, tindakan, kedaluwarsa, dan status sekali pakai.
  • Sleep di memori selama berhari-hari → restart dan penskalaan akan menghilangkan waktu tunggu → simpan timer secara persisten dan bangunkan melalui scheduler.
  • Mengedit snapshot secara langsung → replay akan menghasilkan hasil yang berbeda → gunakan perintah state machine yang terotorisasi dan audit event.
  • Berbagi satu antrean untuk semua tenant → hot tenant membuat tenant lain kelaparan sumber daya (starvation) → partisi, terapkan kuota, prioritaskan, dan gunakan backpressure.
  • Membiarkan definisi baru memengaruhi run lama → alur workflow yang sedang berjalan menjadi tidak dapat dijelaskan → kunci versi (pin version) dan lakukan migrasi secara eksplisit.

Pertanyaan lanjutan dan jawaban

Pertanyaan lanjutan 1: Aktivitas berhasil tetapi worker mengalami crash sebelum menulis hasilnya. Bisakah percobaan ulang (retry) menagih biaya dua kali?

Jika layanan downstream mendukung kunci idempotensi, coba lagi dengan kunci yang sama dan petakan hasil yang sudah selesai. Jika tidak, jangan mencoba lagi secara membabi buta: lakukan kueri pada state downstream, alihkan ke penanganan manusia, atau lakukan kompensasi. State machine dapat membuat event-nya sendiri konsisten, tetapi tidak dapat menciptakan semantik pembayaran exactly-once dengan sendirinya.

Pertanyaan lanjutan 2: Seorang approver mengklik setujui dua kali. Apa yang terjadi?

Izinkan satu penggunaan token yang berhasil dengan conditional update atau batasan keunikan dari pending ke approved. Permintaan kedua mengembalikan respons sudah diproses atau kedaluwarsa dan tidak memajukan workflow. Kedua permintaan dan identitas tetap tercatat di jejak audit.

Pertanyaan lanjutan 3: Bagaimana cara mendukung "dua approver mana pun"?

Simpan inbox persetujuan dan versi kebijakan secara persisten. Catat satu keputusan yang telah dideduplikasi per approver, termasuk snapshot otorisasi. Lanjutkan hanya ketika kuorum tercapai; penolakan, pencabutan, dan penggantian approver adalah perintah eksplisit.

Pertanyaan lanjutan 4: Seorang operator perlu melewati (skip) suatu langkah secara mendesak. Apa jalur yang aman?

Tentukan peran yang diotorisasi, langkah yang dapat dilewati, dan kondisi keamanan terlebih dahulu. Terbitkan perintah StepSkipped disertai alasan dengan state lama, state baru, operator, dan persetujuan. Jika tindakan skip melanggar invarian bisnis, tolak dan tawarkan kompensasi atau penghentian alih-alih mengedit database.

Pertanyaan lanjutan 5: Bagaimana cara menghentikan tenant agar tidak membuat workflow tanpa batas?

Batasi langkah, kedalaman percabangan, konkurensi aktivitas, ukuran riwayat, jumlah timer, dan total waktu proses per tenant. Validasi definisi secara statis dan ukur eksekusinya. Melebihi kuota akan menjeda atau menolak pekerjaan dengan alasan yang terlihat oleh operator, alih-alih membiarkan pertumbuhan tanpa batas.

Sumber publik

Pertanyaan terkait

Alat wawancara terkait

Gunakan Jawab untuk jawaban desain sistem

Perjelas persyaratan terlebih dahulu, lalu lanjutkan dengan skala, arsitektur, pilihan komponen, dan trade-off.

Lihat alat