Haruskah satu kegagalan gagal operasi massal?

11

Di API yang saya kerjakan ada operasi penghapusan massal yang menerima array ID:

["1000", ..., "2000"]

Saya bebas untuk menerapkan operasi hapus seperti yang saya inginkan, jadi saya memutuskan untuk membuat semuanya transaksional: yaitu, jika satu ID tidak valid, seluruh permintaan gagal. Saya akan menyebutnya mode ketat .

try{
savepoint = conn.setSavepoint();

for(id : IDs)
    if( !deleteItem(id) ){
        conn.rollback(savepoint);
        sendHttp400AndBeDoneWithIt();
        return;
    }

conn.commit();
}

Alternatif (diimplementasikan di tempat lain dalam rangkaian perangkat lunak kami) adalah melakukan apa yang dapat kami lakukan di backend, dan melaporkan kegagalan dalam sebuah array. Bagian dari perangkat lunak itu menangani permintaan yang lebih sedikit sehingga responsnya tidak berakhir menjadi array raksasa ... secara teori.


Bug baru-baru ini terjadi di server yang miskin sumber daya membuat saya melihat kode lagi, dan sekarang saya mempertanyakan keputusan awal saya - tetapi kali ini saya lebih termotivasi oleh kebutuhan bisnis daripada praktik terbaik. Jika, misalnya, saya gagal seluruh permintaan, pengguna harus mencoba lagi sedangkan jika sejumlah item dihapus, pengguna dapat menyelesaikan tindakan dan kemudian meminta administrator untuk melakukan sisanya (sementara saya bekerja memperbaiki bug !). Ini akan menjadi mode permisif .

Saya mencoba mencari online untuk beberapa panduan tentang masalah ini tetapi saya datang dengan tangan kosong. Jadi saya datang kepada Anda: Apa yang paling diharapkan dari operasi massal seperti ini? Haruskah saya bertahan dengan lebih ketat, atau haruskah saya lebih permisif?

sumpah
sumber
9
Tergantung. Berapa biaya untuk sesuatu yang tidak dihapus padahal seharusnya? (Biaya didefinisikan sebagai data buruk, sakit kepala, perilaku yang tidak diinginkan, waktu yang diperlukan admin untuk memperbaikinya, dll.) Apakah itu dapat diterima? Jika Anda dapat hidup dengan konsekuensi tidak gagal segalanya, lakukanlah. Jika itu akan menyebabkan terlalu banyak masalah, jangan. Anda tahu perangkat lunak Anda dan konsekuensinya, jadi Anda harus membuat penilaian.
Becuzz
1
@Becuzz Biaya akan menjadi pengguna memperhatikan satu atau dua sisa makanan dan membuka tiket tentang itu; situasi saat ini adalah "omg delete is broken". Untungnya pengguna berada di koridor sehingga tidak terlalu banyak masalah saat ini. Intinya adalah, saya suka melakukan hal yang benar jika memungkinkan, dan dengan basis kode 10+ tahun, Tuhan tahu beberapa hal dapat dilakukan dengan benar
rath
Saya pikir ini juga tergantung pada apakah Anda ingin skalabilitas atau tidak. Jika Anda tidak berniat memiliki banyak ID, itu tidak terlalu menjadi masalah. Jika Anda berniat memiliki sejuta ID, atau lebih baik lagi, tidak sepenuhnya yakin itu tidak akan terjadi, maka Anda dapat menghabiskan satu jam menghapus ID hanya untuk menyetel ulang sepenuhnya karena 1 ID tidak valid.
imnota4
1
@ imnota4 Poin bagus yang belum saya pertimbangkan. UI membatasi permintaan hingga maksimum sekitar 250, tetapi backend tidak memiliki batasan. Bolehkah saya meminta Anda memposting ulang komentar Anda sebagai jawaban?
rath
1
Mode permisif juga membuat pekerjaan Admin lebih mudah karena mereka tidak perlu mereproduksi kegagalan dengan semua tumpukan id. Mungkin bermanfaat juga untuk menginformasikan dalam respons penyebab setiap kesalahan. Melihat penyebabnya, pengguna akhir mungkin bisa menyelesaikannya tanpa tiket "omg delete is broken".
Laiv

Jawaban:

9

Tidak apa-apa untuk melakukan versi endpoint penghapusan yang 'ketat' atau 'bagus', tetapi Anda harus memberi tahu pengguna dengan jelas apa yang terjadi.

Kami sedang melakukan tindakan hapus dengan titik akhir ini. Mungkin DELETE /resource/bulk/atau yang serupa. Saya tidak pilih-pilih. Yang penting di sini adalah bahwa tidak masalah jika Anda memutuskan untuk bersikap tegas atau baik, Anda harus melaporkan kembali apa yang terjadi.

Misalnya, API tempat saya bekerja memiliki DELETE /v1/student/titik akhir yang menerima ID massal. Kami secara teratur mengirimkan permintaan selama pengujian, mendapatkan 200respons, dan menganggap semuanya baik-baik saja, hanya untuk mengetahui nanti bahwa semua orang dalam daftar masih dalam database (tidak aktif) atau tidak benar-benar dihapus karena kesalahan yang mengacaukan panggilan mendatang GET /v1/studentkarena kami mendapatkan kembali data yang tidak kami harapkan.

Solusi untuk ini datang dalam pembaruan kemudian yang menambahkan isi tanggapan dengan id yang tidak dihapus. Setahu saya - ini adalah praktik terbaik.

Intinya, apa pun yang Anda lakukan, pastikan Anda memberikan cara agar pengguna akhir tahu apa yang terjadi, dan mungkin mengapa itu terjadi. Yaitu, jika kita memilih format yang ketat, jawabannya bisa saja 400 - DELETE failed on ID 1221 not found. Jika kami memilih versi 'bagus', itu bisa jadi 207 - {message:"failed, some ids not deleted", failedids:{1221, 23432, 1224}}(permisi format json saya yang malang).

Semoga berhasil!

Adam Wells
sumber
6
207 Multi-Statusmungkin cocok untuk respons kegagalan parsial itu
Richard Tingle
1
KITA PERGI! Aku tidak bisa mengingatnya! Saya akan melanjutkan dan memperbarui jawabannya dengan itu, karena itu sebenarnya sesuai dengan standar.
Adam Wells
2

Seseorang harus tegas dan permisif.

Biasanya, muatan curah dipecah menjadi 2 fase:

  • Validasi
  • Memuat

Selama fase validasi, setiap catatan dilihat secara ketat untuk memastikan memenuhi persyaratan spesifikasi data. Seseorang dapat dengan mudah memeriksa 10 dari 1000 catatan hanya dalam beberapa detik. Catatan yang valid ditempatkan di file baru untuk dimuat, yang tidak sah ditandai dan dihapus dan biasanya dimasukkan ke dalam file terpisah (lewati file). Pemberitahuan kemudian dikirim pada catatan yang gagal validasi sehingga mereka dapat diperiksa dan didiagnosis untuk tujuan pemecahan masalah.

Setelah data divalidasi, kemudian dimuat. Biasanya dimuat dalam batch jika cukup besar untuk menghindari transaksi berjalan lama atau jika ada kegagalan akan lebih mudah untuk dipulihkan. Ukuran batch tergantung pada seberapa besar kumpulan data. Jika satu hanya memiliki 1000 catatan, satu kumpulan akan baik-baik saja. Di sini Anda bisa agak permisif dengan kegagalan, tetapi orang mungkin ingin menetapkan ambang batch yang gagal untuk menghentikan seluruh operasi. Mungkin jika [N] kumpulan gagal, satu akan menghentikan seluruh operasi (jika server sedang down atau sesuatu yang serupa). Biasanya, tidak ada kegagalan pada saat ini karena data telah divalidasi, tetapi jika ada karena masalah lingkungan atau lainnya, cukup muat ulang batch yang gagal. Ini membuat pemulihan sedikit lebih mudah.

Jon Raynor
sumber
Saya tidak memvalidasi ID terhadap nilai-nilai DB, saya hanya mencoba untuk menghapusnya dan melihat bagaimana hasilnya, atau itu akan berlangsung selamanya. Batalkan setelah kegagalan N tampaknya merupakan saran yang sangat masuk akal, +1
rath
2

Haruskah satu kegagalan gagal operasi massal?

Tidak ada jawaban kanonik untuk ini. Kebutuhan dan konsekuensi terhadap pengguna perlu diperiksa, dan trade-off dinilai. OP memberikan beberapa informasi yang diperlukan, tetapi inilah cara saya akan melanjutkan:

Pertanyaan 1 : 'Apa akibatnya bagi pengguna jika satu penghapusan gagal?'

Jawabannya harus mendorong sisa desain / perilaku yang diimplementasikan.

Jika, seperti yang dinyatakan OP, itu hanya pengguna yang memperhatikan pengecualian dan membuka tiket bermasalah, tetapi sebaliknya tidak terpengaruh (item yang tidak dihapus tidak memengaruhi tugas berikutnya), maka saya akan pergi dengan permisif dengan pemberitahuan otomatis kepadamu.

Jika penghapusan gagal perlu diselesaikan sebelum pengguna dapat melanjutkan, maka ketat jelas lebih disukai.

Memberi pengguna opsi (misalnya, pada dasarnya bendera pengabaian-gagal dengan ketat atau permisif sebagai default) mungkin merupakan pendekatan yang paling ramah pengguna.

Pertanyaan 2 : 'Apakah akan ada masalah koherensi / konsistensi data jika tugas berikutnya dilakukan dengan item yang tidak dihapus masih ada di penyimpanan data?'

Sekali lagi, jawabannya akan mendorong desain / perilaku terbaik. Ya -> Ketat, Tidak -> Permisif, Mungkin -> Ketat atau Dipilih Pengguna (terutama jika pengguna dapat diandalkan untuk secara akurat menentukan konsekuensi).

Kristian H
sumber
0

Saya pikir ini tergantung pada apakah Anda ingin skalabilitas atau tidak. Jika Anda tidak berniat memiliki banyak ID, itu tidak terlalu menjadi masalah. Jika Anda berniat memiliki sejuta ID, atau lebih baik lagi, tidak sepenuhnya yakin itu tidak akan terjadi, maka Anda dapat menghabiskan satu jam menghapus ID hanya untuk menyetel ulang sepenuhnya karena 1 ID tidak valid.

imnota4
sumber
-1

Saya akan mengatakan satu poin penting di sini adalah apa artinya sebagian besar barang dihapus.

Apakah ID ini entah bagaimana terkait secara logis, atau hanya kenyamanan / kinerja - pengelompokan batch ini?

Dalam hal entah bagaimana, bahkan secara longgar, terhubung, saya akan pergi untuk strict. Jika itu hanya mode batch (mis. Pengguna mengklik "save" untuk menit-menit terakhir pekerjaannya, dan hanya setelah itu batch dikirimkan) maka saya akan pergi untuk permissiveversinya.

Seperti yang dinyatakan oleh jawaban yang lain: Bagaimana pun, beri tahu "pengguna" apa yang terjadi.

Martin Ba
sumber