Apakah REST hanya terbatas pada kontrol konkurensi yang optimis?

9

Konteks

Karena kewarganegaraan gaya arsitektur REST yang melibatkan setiap permintaan berdiri sendiri, menyebabkan server tidak pernah menyimpan informasi tentang klien.

Dengan demikian, kontrol konkurensi pesimis tidak cocok karena akan mengharuskan server menyimpan klien mana yang mendapatkan kunci pada sumber daya. Kontrol konkurensi optimis kemudian digunakan, dengan bantuan Etagtajuk. (btw, seperti yang saya tanyakan di sana /programming/30080634/concurrency-in-a-rest-api )

Masalah

Masalah utama dengan mekanisme kontrol konkurensi optimis adalah bahwa Anda mengizinkan sepanjang waktu, semua klien, untuk melakukan operasi apa pun.

Dan saya ingin menghindari itu tanpa melanggar prinsip statelessness REST. Maksud saya, semua klien tidak dapat melakukan operasi apa pun kapan saja.

Pertanyaan

Dalam pikiran saya, itu mungkin dengan mekanisme kontrol konkurensi semi-optimis , seperti itu:

  • Klien dapat meminta token
  • Hanya satu token yang dapat dibuat dan memiliki masa berlaku terbatas
  • Untuk melakukan operasi pada sumber daya (seperti POST atau PUT ), klien harus memberikan token ini sebagai bagian dari tubuh (atau header?) Dari permintaan. Klien yang tidak memiliki token tidak dapat melakukan operasi ini.

Ini sangat mirip dengan kontrol konkurensi optimis, kecuali bahwa hanya satu klien yang dapat melakukan beberapa operasi (yang mendapatkan token) ... di kebalikan dari "semua klien dapat melakukan semua operasi".

Apakah mekanisme ini kompatibel dengan gaya arsitektur REST? Apakah itu melanggar salah satu kendala? Saya berpikir untuk bertanya pada SO, tetapi ini tampaknya lebih merupakan pertanyaan tingkat tinggi, terkait dengan desain perangkat lunak.

AilurusFulgens
sumber
1
Ini agak sederhana, sebenarnya: Anda harus memodelkan secara Transactioneksplisit sebagai Sumber Daya.
Jörg W Mittag
Apa yang berubah? Tidak yakin untuk memahami komentar Anda. Saya tidak melakukan kontrol konkurensi untuk transaksi, tetapi untuk mengatakan kepada klien "ok sekarang, Anda benar-benar yakin tidak ada yang akan mengubah sumber daya" (karena mendapat token unik).
AilurusFulgens
1
Apa bedanya? Di satu sisi, Anda menggunakan Etag untuk memeriksa, siapa yang diizinkan untuk memperbarui versi "saat ini"; jika berbenturan, Anda harus memperbarui versi dan melakukan pembaruan setelah itu. Di sisi lain, Anda memiliki mekanisme "mengunci": satu diizinkan, yang lain harus menunggu. Kedengarannya sama. Kelemahan dari pendekatan kedua: 2 permintaan - 1 untuk kunci dan 1 untuk pembaruan. Dalam kasus optimal, Anda hanya memiliki satu pembaruan melalui pendekatan Etag.
Thomas Junk
Nah, secara umum berbicara tentang kontrol konkurensi ... yang kedua yang "kalah dalam lomba" harus selalu menunggu (hanya untuk alasan yang berbeda, saya setuju dengan itu). Perbedaan dengan Etag? Dengan EtagAnda tidak pernah yakin bahwa operasi Anda akan selesai, Anda dapat memiliki situasi di mana Anda tidak akan pernah melakukan operasi apa pun. Dengan kunci, Anda yakin setidaknya untuk melakukan operasi Anda. Jadi, memiliki kunci sederhana hanyalah perantara antara lingkungan di mana "konflik tinggi" dan "konflik langka" dapat terjadi.
AilurusFulgens

Jawaban:

3

Anda tidak boleh (seperti yang tidak pernah PERNAH) mengunci sumber daya apa pun sambil menunggu interaksi pengguna.

Pada titik tertentu, beberapa pengguna Anda akan pergi untuk akhir pekan yang panjang meninggalkan beberapa catatan penting terkunci.

Ah, tetapi Anda tidak akan membiarkan itu terjadi karena Anda memiliki skema penyelesaian timeout / deadlock yang cerdas; kemudian pada beberapa titik ini akan menjadi sangat salah dan pengguna yang mendapat pesan "widget Anda telah dipesan" yang bagus akan berteriak di help desk meminta untuk mengetahui mengapa widgetnya tidak terkirim.

Kebanyakan orang dapat menangani pesan "maaf pengguna lain baru saja memesan bagian ini".

James Anderson
sumber
Anda menjelaskannya dengan baik. Meskipun saya tidak sepenuhnya yakin dengan kalimat pertama Anda: pada titik tertentu Anda akan menjamin bahwa tidak ada orang lain selain Anda yang dapat melakukan pemesanan. Tapi yah, kalimat terakhir Anda adalah ringkasan yang baik, dalam 99% kasusnya.
AilurusFulgens
1
Jika Anda perlu mengunci catatan untuk pengguna tertentu maka lakukan di tingkat aplikasi. Entah akan atribut "LockedBy" sederhana, atau, dengan beberapa versi yang lebih canggih dan mekanisme alur kerja.
James Anderson
Apa yang Anda maksud dengan "di level aplikasi"? Jika Anda menambahkan atribut "LockedBy" pada sumber daya Anda, maka Anda menyimpan informasi tentang klien di server Anda. Atau mungkin saya tidak mengerti komentar Anda. Jika Anda dapat memberikan beberapa detail, akan sangat bagus!
AilurusFulgens
1
@AilurusFulgens - Anda menambahkan atribut LockedBy (dan mungkin cap waktu LockedOn) ke database Anda. Dalam kode aplikasi Anda, Anda menetapkan nama pengguna dan waktu setiap kali klien memulai interaksi pembaruan. Anda membatalkannya ketika klien selesai - Anda kemudian perlu menyusun beberapa aturan bisnis untuk menyelesaikan konflik dan waktu habis dll.
James Anderson
2

Menggunakan token sangat umum di API, token ini biasanya dikirim sebagai header dan memiliki siklus hidup yang jelas. Pikirkan misalnya OAuth.

Terlepas dari bahasa atau kerangka kerja pemrograman Anda, API REST serupa.

Saya dapat memikirkan beberapa skenario di mana Anda ingin membatasi konkurensi, dua di antaranya adalah:

  1. Banyak klien yang memperbarui sumber daya yang sama seperti baris basis data. Misalnya: dua permintaan bersamaan, satu menghapus catatan dan yang lainnya mencoba memperbarui catatan yang sama. Bergantung pada basis data Anda dan bagaimana Anda mengaturnya, Anda mungkin mendapatkan kunci pada catatan atau operasi yang tidak valid karena data akan berbeda atau tidak akan ada.

  2. Pengguna super atau administrator melakukan tindakan khusus dengan API.


Apa yang harus dilakukan dalam kasus ini?

  1. Gunakan transaksi dalam database, lajang, kunci dan mekanisme serupa untuk menyinkronkan akses ke sumber daya.

  2. Token mungkin berfungsi, saya pikir akan lebih baik jika Anda tidak menyimpan informasi tentang klien, hanya tentang token itu sendiri. Pada satu langkah Anda dapat memvalidasi pengguna dan menetapkan token. Maka cukup validasikan bahwa token itu hidup dan valid. Gunakan token yang dapat didekripsi untuk mendapatkan informasi tambahan. Anda dapat menyimpan jika ini adalah token khusus dan hanya memungkinkan pada satu waktu. Dengan cara ini Anda memvalidasi token, bukan pengguna.

Saya harap ini membantu.

Pablo Granados
sumber
Ya, saya mengharapkan tanggapan tentang kemiripan token dan mekanisme OAuth. Meskipun yang terakhir didedikasikan untuk otentikasi. Saya tidak mengerti maksud skenario Anda 1. Bagian sulit untuk menangani konkurensi dalam REST API adalah menjaga batasan statelessness ... artinya server tidak menyimpan informasi tentang klien. Skenario 2 Anda persis seperti apa yang saya lakukan saat ini! :)
AilurusFulgens
Apakah saya menjawab pertanyaan Anda?
Pablo Granados
Tidak maaf Saya mengubah jawaban Anda karena memberikan gambaran yang baik tentang masalah tetapi sayangnya, imo, itu tidak benar-benar menanganinya.
AilurusFulgens
0

SISA saja terlalu primitif, sungguh. Anda dapat memulai dengan REST, tetapi pada akhirnya, aplikasi kaya Anda akan membutuhkan kueri dengan gabung dan pembaruan dengan transaksi. Setiap pengembang yang mencoba menambahkan hal-hal ini sendiri akan rentan kesalahan dan tidak konsisten. Untungnya, ada standar baru yang disebut OData yang melakukan hal itu. Itu lapisan di atas REST dan menyediakan (1) bahasa permintaan yang memungkinkan untuk bergabung sederhana menggunakan properti navigasi (tanpa harus mengekspos kunci asing), dan, (2) pemrosesan batch yang mencakup set perubahan atom.

Lihat di sini untuk (1) https://stackoverflow.com/a/3921423/471129 , dan,

Lihat di sini dan untuk (2) https://stackoverflow.com/a/21939972/471129

Erik Eidt
sumber