- Futurelock adalah fenomena deadlock yang terjadi ketika satu task mengelola beberapa Future sekaligus, lalu salah satunya membutuhkan resource milik Future lain tetapi tidak lagi di-poll
- Mudah terjadi saat konstruksi
tokio::select! menggunakan Future yang direferensikan (&mut future) bersama branch yang mengandung await
- Masalah ini berasal dari gagalnya pemisahan tanggung jawab antara task dan Future, sehingga task yang sama menunggu dua Future tetapi hanya mem-poll salah satunya dan akhirnya berhenti total
- Bentuk serupa juga bisa muncul pada FuturesUnordered, bounded channel, Stream, dan lainnya
- Kunci desain asinkron yang aman adalah memisahkan Future ke task terpisah dengan
tokio::spawn atau menghindari penggunaan await di dalam select
Konsep dan contoh Futurelock
- Futurelock terjadi ketika Future A yang memegang resource dibutuhkan oleh Future B, tetapi task yang menangani keduanya tidak lagi mem-poll A
- Pada kode contoh,
tokio::select! menunggu &mut future1 dan sleep secara bersamaan; jika sleep selesai lebih dulu, future1 tetap berada dalam status menunggu lock
- Setelah itu
future3 meminta lock yang sama, tetapi lock sudah dialokasikan ke future1 dan future1 tidak dipoll lagi, sehingga program berhenti selamanya
Interaksi tokio::select! dan Mutex
tokio::sync::Mutex adalah lock yang fair, yaitu memberi lock sesuai urutan antrean
- Lock diberikan kepada
future1, tetapi task sudah hanya mem-poll future3, sehingga future1 tidak pernah berjalan
- Mutex hanya bertugas membangunkan task penunggu berikutnya, dan tidak tahu Future mana yang benar-benar sedang dipoll
Penyebab umum Futurelock
- Struktur dependensi melingkar ketika task T menunggu Future F1, F1 bergantung pada F2, dan F2 kembali membutuhkan polling dari T
- Umumnya terjadi dalam situasi berikut
- Menggunakan
&mut future di tokio::select! lalu menjalankan await di branch lain
- Pada
FuturesOrdered atau FuturesUnordered, setelah sebagian Future selesai lalu melakukan pekerjaan asinkron lain
- Perilaku serupa pada Future yang diimplementasikan secara manual
Kasus pada Stream dan struktur lain
- Pada
FuturesOrdered atau FuturesUnordered, Futurelock bisa terjadi setelah sebuah Future diambil lalu sistem menunggu Future lain yang memakai resource terkait
join_all tidak menimbulkan Futurelock karena terus mem-poll semua Future
Kasus nyata dan debugging
- Dalam kasus Omicron#9259, semua Future akses database terkena Futurelock sehingga request HTTP menunggu tanpa batas
- Pengiriman pada kanal
mpsc terblokir, tetapi sisi penerima terlihat kosong sehingga penyebabnya sulit diidentifikasi
- Saat debugging, alat seperti
tokio-console dapat membantu, tetapi dalam banyak kasus pelacakan akar masalah sangat sulit
Pedoman pencegahan Futurelock
- Saat satu task mem-poll beberapa Future, jangan sampai polling terhadap Future yang sudah dimulai dihentikan di tengah jalan
- Jika memungkinkan, spawn Future sebagai task baru agar berjalan mandiri
- Jika
JoinHandle diteruskan ke tokio::select!, risiko Futurelock hilang
- Hal yang perlu diperhatikan saat memakai
tokio::select!
- Jangan gunakan
&mut future dan await secara bersamaan
- Jika kedua kondisi itu ada sekaligus, risiko Futurelock menjadi tinggi
- Saat memakai
Stream, gunakan JoinSet untuk menjalankan tiap Future di task terpisah
- Menambah kapasitas
bounded channel bukan solusi mendasar
- Sebagai gantinya,
try_send() dapat dipakai untuk menghindari blocking
Pola penghindaran yang keliru
- Menaikkan kapasitas channel tanpa batas tidak realistis dan menimbulkan efek samping seperti latensi dan penggunaan memori yang lebih besar
- Mencoba menghilangkan dependensi antar-Future juga rapuh karena dependensi baru bisa muncul saat maintenance
- Satu-satunya cara yang benar-benar aman adalah memisahkan task dengan
tokio::spawn
Perbaikan ke depan dan pertimbangan keamanan
- Ada kemungkinan menambahkan peringatan melalui lint Clippy saat
tokio::select! memakai &mut future atau mengandung await
- Futurelock bisa disalahgunakan sebagai bentuk penolakan layanan (DoS), tetapi pada dasarnya ini adalah perilaku abnormal sehingga perlu dicegah
Belum ada komentar.