Topik ini memperkenalkan supervisor, proses yang satu-satunya pekerjaan adalah mengawasi proses lain dan memulai ulang yang gagal. Pembahasan mencakup spesifikasi child dalam bentuk map, strategi restart bawaan, dan intensitas restart sebagai pengaman loop tak berujung. Contohnya menempatkan server tiket dari topik gen_server di bawah pengawasan.
Tugas dan bentuk supervisor#
Supervisor adalah proses OTP yang memulai child sesuai spesifikasi, memantau setiap childnya, dan memulai ulang yang berakhir sesuai strategi. Ia tidak berisi logika bisnis sama sekali, dan justru karena itu ia dapat dipercaya bertahan paling lama. Modul berikut mengawasi server tiket:
-module(sup_tiket).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
Child = #{id => tiket, start => {tiket, start_link, []},
restart => permanent, shutdown => 5000, type => worker},
{ok, {#{strategy => one_for_one, intensity => 5, period => 10}, [Child]}}.init/1 mengembalikan dua hal: konfigurasi supervisor dan daftar spesifikasi child. Spesifikasi child berbentuk map dengan kunci yang menentukan segalanya: id adalah nama logis di dalam supervisor, start adalah tuple modul-fungsi-argumen untuk memulai, restart menentukan kebijakan restart, shutdown adalah batas waktu berhenti secara teratur dalam milidetik, dan type membedakan worker dari supervisor. Nilai permanent berarti child selalu dimulai ulang, sedangkan nilai transient hanya bila berakhir tidak normal dan temporary tidak pernah.
Mengamati pemulihan#
Sesi berikut memulai supervisor, menghancurkan childnya, lalu melihat hasilnya:
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> c(tiket).
{ok,tiket}
2> c(sup_tiket).
{ok,sup_tiket}
3> sup_tiket:start_link().
{ok,<0.97.0>}
4> whereis(tiket).
<0.98.0>
5> exit(whereis(tiket), mati).
=SUPERVISOR REPORT==== 3-Nov-2026::11:33:26.545540 ===
supervisor: {local,sup_tiket}
errorContext: child_terminated
reason: mati
offender: [{pid,<0.98.0>},
{id,tiket},
{mfargs,{tiket,start_link,[]}},
{restart_type,permanent},
{significant,false},
{shutdown,5000},
{child_type,worker}]
true
6> timer:sleep(200).
ok
7> whereis(tiket).
<0.101.0>
8> Penghancuran memicu dua hal sekaligus. Supervisor mencetak supervisor report ke logger yang memuat konteks child_terminated, alasan mati, dan identitas lengkap child yang bermasalah, sehingga kejadian itu tertinggal sebagai jejak operasional. Lalu supervisor memulai ulang child dari spesifikasi yang sama, dan whereis/1 menunjukkan PID baru <0.101.0>. Nama terdaftar langsung menempel pada proses baru, sehingga pengguna layanan tidak perlu tahu apa pun tentang kejadian itu.
Strategi restart#
Kunci strategy menentukan siapa yang ikut dimulai ulang saat satu child gagal. Strategi one_for_one hanya memulai ulang child yang mati, pilihan bila child berdiri sendiri. Strategi one_for_all memulai ulang seluruh child saat satu mati, dipakai bila seluruh child berbagi state yang dibangun bersama sehingga satu kegagalan meragukan semuanya. Strategi rest_for_one memulai ulang child yang mati beserta semua child yang dimulai setelahnya, berguna bila child yang dimulai kemudian bergantung pada child yang dimulai lebih dulu. Penataan urutan child di daftar spesifikasi adalah bagian dari desain karena strategi rest_for_one membaca urutan itu secara harfiah.
Intensitas restart#
Dua kunci lainnya menjadi pengaman: intensity dan period. Konfigurasi intensity => 5, period => 10 berarti paling banyak lima restart dalam sepuluh detik, dan pelanggarannya membuat supervisor mengakhiri dirinya beserta seluruh anak cucunya. Aturan ini mencegah loop restart tak berujung pada child yang cacat struktural, misalnya crash seketika setiap kali dimulai, yang tanpa pengaman akan memakan prosesor tanpa henti. Supervisor yang menyerah justru bagian dari desain: kesalahan yang menyebar ke level lebih tinggi diberi kesempatan untuk diperbaiki oleh pihak yang lebih tinggi pula, dan urutan itu dituntaskan pada topik pohon supervisi.
Kelola child secara manual#
Selain memulai ulang otomatis, supervisor menyediakan pengelolaan manual untuk operasi pemeliharaan. Fungsi count_children/1 merangkum isi supervisor, terminate_child/2 menghentikan child tanpa memicu restart otomatis, dan restart_child/2 memulainya kembali secara manual:
1> c(tiket).
{ok,tiket}
2> c(sup_tiket).
{ok,sup_tiket}
3> sup_tiket:start_link().
{ok,<0.97.0>}
4> supervisor:count_children(sup_tiket).
[{specs,1},{active,1},{supervisors,0},{workers,1}]
5> supervisor:terminate_child(sup_tiket, tiket).
ok
6> whereis(tiket).
undefined
7> supervisor:restart_child(sup_tiket, tiket).
{ok,<0.103.0>}
8> whereis(tiket).
<0.103.0>Perhatikan perilaku terminate_child/2 pada child bertipe permanent: proses dihentikan dan tidak dimulai ulang, karena penghentian manual adalah perintah yang disengaja, bukan kegagalan yang harus dipulihkan. Pasangan terminate dan restart inilah alat pemeliharaan yang benar untuk mengganti child secara terkendali, sebagaimana dipakai mekanisme pembaruan kode pada hot code upgrade.
Kesalahan umum#
- Menyediakan child yang gagal seketika karena konfigurasi salah. Supervisor menghitung kegagalan itu pada intensitasnya, dan cepat atau lambat menyerah. Periksa laporan supervisor, bukan hanya PID yang hidup.
- Memilih strategi berdasarkan selera, bukan ketergantungan.
one_for_allyang dipakai pada child yang sebenarnya berdiri sendiri memulai ulang semua pihak tanpa alasan, sedangkanone_for_onepada child yang berbagi state membuat pasangan yang tidak sinkron tetap berjalan. - Menaruh logika bisnis di supervisor. Supervisor yang sibuk mengerjakan logika bisnis tidak lagi memantau. Ia harus bisa menjawab pesan sistem OTP seketika saat childnya mati.
- Mengira terminate_child akan memicu restart. Penghentian manual bukan kegagalan, sehingga supervisor tidak bertindak. Pemulihan dilakukan dengan restart_child atau dengan mengakhiri proses lewat exit, yang terekam sebagai kegagalan.
Ringkasan#
- Supervisor memulai child dari spesifikasi map dan memulai ulang yang berakhir sesuai strategi, tanpa berisi logika bisnis.
- Kunci restart menetapkan kebijakan per child: permanent selalu, transient hanya saat tidak normal, dan temporary tidak pernah.
- Strategi one_for_one, one_for_all, dan rest_for_one menentukan siapa yang ikut dimulai ulang, dan urutan daftar child adalah bagian desainnya.
- Intensity dan period mengakhiri supervisor yang restart berlebihan, sehingga kegagalan struktural naik ke level yang lebih tinggi.
Referensi#
- supervisor — Ericsson — Konsep resmi supervisor, spesifikasi child, strategi, dan intensitas restart.
- Erlang Design Principles: Supervision — Ericsson — Kerangka desain aplikasi OTP tempat supervisor berada.
- Learn You Some Erlang for Great Good! — Fred Hebert — Bab supervisor dengan contoh spesifikasi dan strategi.