Apa praktik terbaik untuk menangani kesalahan dalam tindakan multi-langkah antara klien dan server?
Saya memiliki situs web yang mengunggah posting pekerjaan ke API saya, ada beberapa langkah untuk melakukan ini:
Unggah gambar logo ke penyimpanan file.
Masukkan data tentang lowongan pekerjaan ke dalam database.
Proses pembayaran dengan penyedia pihak ketiga.
Kirim email melalui penyedia pihak ketiga.
Secara umum, Anda dapat membayangkan langkah-langkah lain hadir di sini dalam aplikasi yang berbeda, misalnya mendapatkan beberapa informasi dari API pihak ketiga, memvalidasi ReCAPTCHA, memperbarui API Pengindeksan Google, mengirim SMS, dll., Dll.
Karena semua ini menggunakan pihak ke-3 dan tidak bergantung pada server yang menangani panggilan API, salah satu dari mereka dapat gagal meninggalkan beberapa langkah dengan sukses dan yang lainnya tidak (mis. Logo diperbarui tetapi pembayaran tidak dikumpulkan).
Pertanyaan saya adalah bagaimana kesalahan dalam tindakan multi-langkah semacam ini antara klien dan server biasanya ditangani dalam sistem produksi? Apakah ada standar atau praktik terbaik yang diterima?
Saya telah mempertimbangkan:
Tidak menangani kesalahan dan hanya berharap semuanya berjalan tanpa kesalahan.
Mendefinisikan fungsi 'batalkan' di backend untuk setiap langkah dan jika salah satu langkah gagal, maka panggil fungsi itu di langkah sebelumnya. Dengan tindakan yang terdiri dari banyak langkah, ini bisa berubah menjadi kode spaghetti dengan cukup cepat, dan beberapa langkah tidak dapat diurungkan dengan mudah - misalnya mengirim email.
Membuat titik akhir terpisah di backend untuk setiap langkah dan membiarkan klien memanggil setiap langkah secara bergantian. Ini juga bisa menggunakan titik akhir API 'urungkan' sehingga jika klien menerima kesalahan pada salah satu langkah, maka klien dapat membatalkan semua langkah sebelumnya. Ini memiliki keuntungan karena memungkinkan klien memperkirakan kemajuan tindakan yang diselesaikan, yaitu dapat menampilkan '1 dari 5 langkah diselesaikan' kepada pengguna.
Membuat baris dalam DB (atau database dalam memori?) Untuk setiap tindakan dan ketika setiap langkah selesai menandai kolom terkait sebagai selesai. Ketika setiap kolom di baris selesai maka mengirimkan tanggapan kembali ke pengguna.
Jawaban
Proses multi-langkah ini adalah transaksi, berpindah dari satu status awal yang konsisten ("tidak ada yang terjadi") ke beberapa status akhir ("posting pekerjaan selesai"), dengan langkah-langkah perantara yang membuat aplikasi Anda (mungkin) dalam status tidak konsisten.
Anda tidak boleh mendelegasikan penanganan transaksi kepada klien Anda, terutama tidak membagi proses menjadi panggilan individu (atau dia mungkin akan melewatkan langkah pembayaran - buruk untuk bisnis).
Jika salah satu langkah gagal, tentu tidak masuk akal untuk melanjutkan, Anda harus melakukan semacam rollback ke kondisi yang dapat diterima, tidak harus status awal. Misalnya, saya tidak melihat keharusan mutlak untuk menghapus gambar yang diunggah dari penyimpanan file.
Pertama, saya akan mencoba mengatur langkah-langkah sedemikian rupa sehingga sebagian besar langkah perantara dapat diterima, jadi tidak perlu melakukan rollback.
Langkah-langkah rumit pasti pembayaran dan email (jika saya memahami bisnis Anda dengan benar).
- Menagih pelanggan tanpa email yang dikirim itu buruk (hampir penipuan).
- Mengirim email tanpa menerima pembayaran berarti kehilangan uang (jika ini tidak sering terjadi, mungkin masih bisa ditoleransi). Anda pasti tidak dapat mengembalikan email, setelah dikirim, tetapi mungkin Anda dapat mengembalikan pembayaran (kecuali jika Anda kehilangan koneksi ke penyedia tepat pada saat itu).
Karena Anda mengandalkan koneksi eksternal, saya tidak melihat cara untuk benar-benar menghindari penyelesaian sebagian transaksi Anda, jadi saya akan merancang prosesnya sedemikian rupa sehingga terjadi kegagalan menengah.
- baik sangat tidak mungkin
- atau tinggalkan keadaan yang dapat ditoleransi.
Jadi, saya akan
- Ping semua layanan pengalaman untuk memastikan mereka saat ini aktif dan dapat dijangkau
- Unggah gambar logo ke penyimpanan file.
- Masukkan data tentang lowongan pekerjaan ke dalam database.
- Kirim email melalui penyedia pihak ketiga.
- Proses pembayaran dengan penyedia pihak ketiga.
Prosedur rollback akan menjadi
- hapus gambar dari penyimpanan file,
- hapus posting pekerjaan dari database,
- Jika email telah dikirim, tetapi pembayaran gagal: jadwalkan permintaan pembayaran untuk coba lagi nanti.
"Terbaik" jelas tergantung pada kebutuhan. Nomor 1 jelas paling sederhana untuk diterapkan tetapi transaksi akan hilang / tidak lengkap jika terjadi kesalahan. Mungkin ini trade-off yang dapat diterima dari perspektif bisnis?
Solusi paling ampuh adalah membagi proses menjadi serangkaian langkah di mana setiap langkah merupakan transaksi. Sebuah transaksi selesai atau gagal, dan jika gagal dapat dicoba kembali dengan aman. (Misalnya mengirim surat atau sms akan menjadi transaksi.) Baris database melacak langkah-langkah yang telah diselesaikan.
Saya tidak berpikir Anda harus meminta klien memanggil setiap langkah. Itu akan membuat kopling yang erat dan hanya meningkatkan kompleksitas. Cukup minta klien memanggil satu permintaan dengan semua data yang diperlukan, yang memulai alur kerja. Klien kemudian dapat mengirim permintaan terpisah dan berkala untuk mengumpulkan status jika Anda ingin menunjukkan kemajuan.
Dukungan untuk pembatalan lebih rumit dan (seperti yang Anda amati) tidak selalu memungkinkan. Jika beberapa langkah dapat gagal dengan cara di mana seluruh proses harus ditolak (seperti jika kartu kredit tidak dapat valid) maka saya pikir itu harus dilakukan dalam langkah validasi sebelum proses multi-langkah dimulai. Ini akan memungkinkan Anda memberikan umpan balik yang sinkron kepada klien dan meminta klien meninjau dan memasukkan kembali data.
Seperti yang disebutkan orang lain, idealnya Anda ingin menggabungkan semua bagian yang diperlukan untuk posting pekerjaan yang sukses dan meminta klien untuk mengirimkannya ke backend Anda dalam satu permintaan. Sebagai pengembang seluler, saya selalu menganjurkan klien untuk bekerja seminimal mungkin untuk menghemat penggunaan data dan masa pakai baterai.
Untuk backend, saya sarankan untuk mencoba memasukkan informasi yang paling penting ke db terlebih dahulu, dan kemudian coba misalnya memasukkan data tambahan setelahnya seperti gambar logo