Topik ini menjelaskan bagaimana kegagalan satu proses diketahui proses lain melalui link: sinyal exit yang menyertainya, perilaku default yang ikut mati, dan trap_exit yang mengubah sinyal menjadi pesan biasa. Mekanisme ini adalah fondasi pola let it crash dan seluruh pohon supervisi yang dituntaskan pada modul OTP behaviour.
Link dan perilaku default#
Fungsi spawn_link/1 membuat proses baru sekaligus menghubungkannya dengan link dua arah ke pembuatnya. Link itu sendiri tidak terlihat oleh program. Yang terlihat adalah akibatnya saat salah satu sisi berakhir. Saat proses berhenti, baik normal maupun karena error, VM mengirim sinyal exit ke semua proses yang ter-link dengannya. Perilaku default penerima sinyal adalah ikut berhenti dengan alasan yang sama, sehingga kegagalan merambat otomatis tanpa kode tambahan.
Perilaku ini bukan efek samping yang tak disengaja, melainkan tujuan desainnya. Program yang benar tidak perlu menelan kegagalan bagian yang sedang bekerja. Ia perlu tahu segera dan mengambil tindakan di tingkat yang mampu memulihkannya. Shell juga proses, dan eksperimen berikut memperlihatkan efek link pada shell itu sendiri:
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]
Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> spawn_link(fun() -> exit(bum) end).
** exception exit: bum
2> flush().
okProses baru memanggil exit/1 untuk mengakhiri dirinya dengan alasan bum, dan sinyal exit itu langsung mengakhiri proses shell yang ter-link. Shell menampilkan ** exception exit: bum lalu melanjutkan dengan proses shell baru, sehingga percobaan ini aman dilakukan di shell, tetapi kesimpulannya jelas: tanpa penangkal, kegagalan merambat.
Trap exit: sinyal menjadi pesan#
Proses dapat menangkal sinyal exit dengan process_flag(trap_exit, true). Sejak itu, sinyal exit dari proses ter-link tidak lagi mengakhiri, melainkan masuk ke mailbox sebagai pesan biasa berupa tuple {'EXIT', PID, Alasan}. Nilai kembalian process_flag/2 adalah nilai lama flag tersebut, yaitu false bila penangkalan belum pernah diaktifkan:
1> process_flag(trap_exit, true).
false
2> P = spawn_link(fun() -> receive after 30000 -> ok end end).
<0.88.0>
3> exit(P, mati).
true
4> flush().
Shell got {'EXIT',<0.88.0>,mati}
okFungsi exit/2 mengirim sinyal exit ke proses P dengan alasan mati, dan karena shell menangkal, pesan {'EXIT',<0.88.0>,mati} tiba di mailbox dan terbaca lewat flush/0. Proses P pada contoh hanya menunggu selama tiga puluh detik, sehingga satu-satunya cara ia berakhir adalah melalui sinyal yang dikirim. Bentuk tuple yang membawa PID pengirim membuat penerima tahu proses mana yang berakhir tanpa menebak.
exit/1 dan exit/2#
Dua fungsi exit sering tertukar padahal arahnya berbeda. exit/1 mengakhiri proses yang memanggilnya dengan alasan yang diberikan, dan bila alasan itu normal, proses berakhir secara normal. exit/2 mengirim sinyal exit ke proses lain. Alasan kill tidak dapat ditangkal dan mengakhiri target tanpa kesempatan penangkalan, sedangkan alasan lain tetap bisa ditangkal oleh trap_exit. Tabel berikut merangkumnya:
| Bentuk | Arah | Penangkal dengan trap_exit |
|---|---|---|
exit(Alasan) | mengakhiri proses pemanggil | ya, kecuali alasan kill |
exit(PID, Alasan) | mengirim sinyal ke proses lain | ya, kecuali alasan kill |
Pilihan kill adalah alat pamungkas: penerima tidak dapat menangkalnya, sehingga supervisor pun ikut berakhir bila menerima sinyal ini. Pemakaian yang disarankan pada kode layanan adalah alasan yang deskriptif, sehingga penerima yang menangkal dapat membaca alasan kegagalannya dari pesan.
Berakhir normal dan unlink#
Dua perilaku lain melengkapi gambar link. Pertama, berakhir secara normal juga mengirim sinyal, dengan alasan normal, dan penerima yang menangkal dapat membedakannya dari kegagalan:
1> process_flag(trap_exit, true).
false
2> P2 = spawn_link(fun() -> ok end).
<0.88.0>
3> flush().
Shell got {'EXIT',<0.88.0>,normal}
okKedua, unlink/1 memutus link, dan sejak itu kegagalan proses terkait tidak lagi diterima. Perhatikan flush/0 yang mengembalikan ok tanpa mencetak pesan apa pun:
4> P3 = spawn_link(fun() -> receive after 30000 -> ok end end).
<0.91.0>
5> unlink(P3).
true
6> exit(P3, uji).
true
7> flush().
okTidak ada pesan 'EXIT' yang tiba setelah pemutusan, sekaligus menegaskan bahwa sinyal hanya mengalir melalui link yang masih hidup. Pasangan spawn dan spawn_link juga lazim dipisah untuk kendali yang lebih halus: proses dibuat dengan spawn/1, masing-masing sisi menyiapkan keadaannya, lalu di-link lewat link/1 bila keduanya siap. Pemisahan ini menambah tanggung jawab kecil, yaitu menangani keadaan proses lawan sudah berakhir sebelum link dibuat, karena link/1 melaporkan noproc pada keadaan itu.
Posisi link dalam desain#
Link menetapkan prinsip yang menjadi dasar OTP: dua proses yang saling bergantung untuk benar harus mati bersama. Layanan yang setengah jalan lebih berbahaya daripada layanan yang mati, karena ia masih mengirim balasan yang salah. Dengan link, proses yang kehilangan pasangannya tidak melanjutkan pekerjaan dalam keadaan meragukan, dan pihak yang menangkal sinyal, yaitu supervisor, memutuskan langkah pemulihannya. Keterbatasan link ada pada simetrinya: satu link mengalirkan sinyal dua arah, sementara kebutuhan mengamati proses lain tanpa ikut mati membutuhkan monitor yang dibahas pada topik Monitor.
Ringkasan#
- spawn_link/1 membuat proses dan menghubungkannya dengan link dua arah, dan sinyal exit mengalir ke kedua arah saat salah satu sisi berakhir.
- Tanpa trap_exit, penerima sinyal exit ikut berakhir dengan alasan yang sama, dan itulah perilaku yang dikehendaki.
- process_flag(trap_exit, true) mengubah sinyal menjadi pesan {‘EXIT’, PID, Alasan} di mailbox, dengan nilai kembalian berupa nilai lama flag tersebut.
- exit/1 mengakhiri proses pemanggil sedangkan exit/2 mengirim sinyal ke proses lain, dan alasan kill tidak dapat ditangkal.
- Link mewujudkan prinsip mati bersama untuk proses yang saling bergantung, dan fondasi pohon supervisi.
Referensi#
- Erlang Reference Manual: Processes — Ericsson — Dokumentasi resmi link, sinyal exit, dan trap_exit.
- Erlang Error Handling Guide — Ericsson — Panduan resmi penanganan error antar proses.
- Learn You Some Erlang for Great Good! — Fred Hebert — Bab error antar proses, link, dan penangkapan sinyal exit.