Handler #
Dalam mengelola infrastruktur modern, efisiensi dan stabilitas adalah dua pilar utama yang menentukan keberhasilan otomatisasi. Banyak aksi dalam administrasi sistem yang bersifat destruktif atau memerlukan waktu pemrosesan yang lama, seperti memulai ulang layanan web server, memuat ulang konfigurasi database, atau menerapkan aturan firewall baru. Jika kita menjalankan aksi-aksi ini pada setiap eksekusi otomatisasi tanpa memperhitungkan apakah ada perubahan nyata pada sistem, kita akan menghadapi risiko downtime yang tidak perlu, degradasi performa, dan pelanggaran prinsip idempotensi.
Ansible memecahkan tantangan ini secara elegan melalui mekanisme handler. Handler adalah task khusus yang bersifat event-driven (digerakkan oleh peristiwa). Berbeda dengan task biasa yang dieksekusi secara linear dari atas ke bawah, handler hanya akan dipanggil jika dan hanya jika ada task lain yang memicu peristiwa perubahan (changed state). Artikel ini akan membedah secara mendalam konsep handler, arsitektur internal pengantrian berbasis host, cara menangani kegagalan eksekusi, serta pola penerapan tingkat lanjut untuk menjaga kestabilan infrastruktur kita.
Desain Event-Driven: Mengapa Kita Butuh Handler? #
Untuk memahami nilai penting dari handler, kita harus melihat bagaimana Ansible memproses status dari setiap task. Ketika Ansible mengeksekusi sebuah modul di managed node, modul tersebut mengembalikan status keluaran. Tiga status yang paling sering kita temui adalah:
- ok: Sistem sudah berada dalam kondisi yang diinginkan. Tidak ada perubahan yang dilakukan.
- changed: Sistem tidak berada dalam kondisi yang diinginkan, sehingga Ansible melakukan tindakan untuk menyelaraskannya.
- failed: Terjadi kesalahan saat mencoba menerapkan status yang diinginkan.
Dalam administrasi sistem konvensional, kita sering kali menggabungkan langkah penulisan konfigurasi dengan langkah memuat ulang (reload) atau memulai ulang (restart) layanan dalam satu urutan yang kaku. Pendekatan ini adalah sebuah anti-pattern dalam dunia otomatisasi.
Dampak Buruk Tanpa Handler #
Jika kita tidak menggunakan handler, layanan target akan selalu di-restart pada setiap kali playbook dijalankan. Bayangkan sebuah kluster web server yang melayani jutaan pengguna. Jika kita menjalankan playbook pemeliharaan rutin hanya untuk memeriksa apakah file konfigurasi nginx masih utuh, dan playbook tersebut secara buta melakukan restart nginx di akhir tugas, kita sengaja menciptakan celah downtime mikro yang mengganggu koneksi aktif pengguna.
Selain itu, dari perspektif efisiensi waktu, memulai ulang layanan database besar seperti PostgreSQL atau MySQL secara tidak perlu akan memicu proses pembersihan cache memori (buffer pool flush) yang menurunkan performa query database selama beberapa menit setelah restart. Oleh karena itu, kita membutuhkan mekanisme cerdas yang memastikan restart hanya terjadi apabila file konfigurasi benar-benar mengalami modifikasi isi.
Perbedaan Fundamental: Handler vs Task Biasa #
Meskipun handler dideklarasikan dengan sintaksis yang hampir sama dengan task biasa (menggunakan modul, argumen, dan opsi penanganan kesalahan yang serupa), keduanya memiliki perbedaan perilaku yang sangat mendasar.
Tabel berikut merangkum perbedaan arsitektur antara task biasa dan handler:
| Karakteristik | Task Biasa | Handler |
|---|---|---|
| Eksekusi Default | Selalu dieksekusi secara berurutan sesuai posisinya di dalam playbook. | Hanya dieksekusi jika dipicu secara eksplisit oleh task lain yang menghasilkan status changed. |
| Waktu Eksekusi | Langsung berjalan begitu giliran antriannya tiba selama fase play berjalan. | Ditangguhkan (deferred) hingga seluruh task utama dalam sebuah play selesai dieksekusi. |
| Frekuensi Eksekusi | Berjalan sebanyak deklarasi yang kita buat (jika ada loop, berjalan sesuai jumlah iterasi). | Hanya berjalan sekali per play untuk setiap host, terlepas dari berapa banyak task yang memicunya. |
| Sensitivitas Kegagalan | Jika task utama gagal, playbook langsung berhenti untuk host tersebut secara default. | Jika play terhenti di tengah jalan karena task utama gagal, antrian handler yang tertunda akan dibatalkan secara default. |
Mari kita amati perbedaan penulisan kode antara pendekatan tanpa handler (anti-pattern) dengan pendekatan menggunakan handler (best-practice).
# ANTI-PATTERN: Memaksa restart layanan pada setiap eksekusi
- name: Mengelola Layanan Web Tanpa Handler
hosts: webservers
tasks:
- name: Menyalin file konfigurasi nginx.conf
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
- name: Memuat ulang layanan nginx (Selalu Berjalan)
systemd:
name: nginx
state: reloaded
# ✗ Aksi ini akan selalu dijalankan meskipun file nginx.conf tidak berubah.
# Hal ini melanggar prinsip idempotensi sejati.
Sekarang, bandingkan dengan pendekatan deklaratif yang memanfaatkan kekuatan handler:
# BENAR: Menggunakan handler untuk memicu aksi hanya saat terjadi perubahan
- name: Mengelola Layanan Web Dengan Handler
hosts: webservers
tasks:
- name: Menyalin file konfigurasi nginx.conf
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Memuat Ulang Nginx
# ✓ Aksi ini memicu handler "Memuat Ulang Nginx" hanya jika status task di atas adalah "changed".
handlers:
- name: Memuat Ulang Nginx
systemd:
name: nginx
state: reloaded
# ✓ Handler ini didefinisikan secara terpisah dan hanya berjalan saat dipicu.
Siklus Hidup dan Mekanisme Antrian Handler #
Satu aspek yang paling sering membingungkan pengguna baru Ansible adalah waktu eksekusi handler. Kita harus memahami bahwa handler tidak langsung dieksekusi begitu task yang memanggilnya selesai dengan status changed.
Ansible menggunakan mekanisme antrian internal (internal handler queue) yang bekerja dengan aturan sebagai berikut:
1. Penundaan Eksekusi (Deferred Execution) #
Ketika sebuah task menghasilkan status changed dan memiliki deklarasi notify: Nama Handler, Ansible akan memasukkan nama handler tersebut ke dalam daftar antrian khusus untuk host yang bersangkutan. Aksi riil dari handler tersebut ditangguhkan sampai seluruh task utama dalam play tersebut selesai diproses untuk semua host.
2. Penggabungan Notifikasi (Notification Coalescing / Deduplication) #
Jika ada beberapa task terpisah yang memicu handler yang sama selama satu play, Ansible cukup memasukkan handler tersebut satu kali ke dalam antrian.
Misalnya, kita memiliki task untuk memperbarui file konfigurasi utama nginx, task untuk memperbarui sertifikat SSL nginx, dan task untuk menyalin file virtual host baru. Ketiga task ini sama-sama memiliki baris notify: Restart Nginx. Jika ketiga task tersebut mendeteksi adanya perubahan (status changed), handler Restart Nginx tetap hanya akan dieksekusi satu kali di akhir play. Penggabungan ini mencegah pemborosan sumber daya akibat proses restart berulang-ulang yang tidak efisien.
3. Pengantrian Spesifik per Host (Host-Specific Queueing) #
Antrian handler dikelola secara independen untuk setiap host yang terdaftar dalam inventory kita. Ini berarti jika kita menjalankan playbook pada sepuluh server web, dan perubahan konfigurasi hanya terjadi pada web-01 dan web-02, maka hanya web-01 and web-02 yang akan mengeksekusi handler tersebut di akhir play. Delapan server lainnya tidak akan mengeksekusi handler karena status tugas mereka adalah ok (tidak ada perubahan).
Berikut adalah representasi diagram Mermaid yang menggambarkan alur pengambilan keputusan pengantrian dan eksekusi handler per host dalam siklus hidup playbook:
flowchart TD
Start(["Mulai Playbook Execution"]) --> LoopTasks["Evaluasi Task Utama untuk Host X"]
LoopTasks --> RunTask{"Eksekusi Task"}
RunTask -- "Error/Failed" --> MarkFailed["Tandai Host sebagai Gagal"]
MarkFailed --> EndPlay["Hentikan Eksekusi Play untuk Host X"]
RunTask -- "Sukses (Status: ok)" --> CheckMore{"Ada Task Lain?"}
RunTask -- "Sukses (Status: changed)" --> HasNotify{"Memiliki Deklarasi 'notify'?"}
HasNotify -- "Ya" --> QueueHandler["Masukkan Handler ke Antrian Host X"]
QueueHandler --> CheckMore
HasNotify -- "Tidak" --> CheckMore
CheckMore -- "Ya" --> LoopTasks
CheckMore -- "Tidak (Semua Task Selesai)" --> CheckQueue{"Apakah Antrian Handler Host X Berisi Item?"}
CheckQueue -- "Tidak" --> FinishPlay(["Selesai (Status: Berhasil)"])
CheckQueue -- "Ya" --> ExecHandlers["Mulai Eksekusi Antrian Handler untuk Host X"]
ExecHandlers --> RunHandler{"Jalankan Handler A"}
RunHandler -- "Sukses" --> NextHandler{"Ada Handler Lain di Antrian?"}
NextHandler -- "Ya" --> RunHandler
NextHandler -- "Tidak" --> FinishPlay
RunHandler -- "Failed" --> AbortHandlers["Batalkan Sisa Antrian Handler"]
AbortHandlers --> FinishPlayWithFail(["Selesai dengan Status: Gagal di Handler"])
Aturan Penulisan Nama dan Pencocokan Identitas #
Ketika kita menulis playbook yang menggunakan handler, Ansible mengandalkan pencocokan string secara tepat untuk menghubungkan bagian notify pada task dengan nama handler di bagian handlers:.
Beberapa aturan penting yang harus kita patuhi demi menghindari kesalahan pencocokan adalah:
- Sensitif terhadap Huruf Besar-Kecil (Case-Sensitive): Notifikasi ke
Restart nginxtidak akan pernah bisa memicu handler yang bernamaRestart Nginx. - Kesesuaian Spasi dan Karakter Khusus: Nama handler harus ditulis sama persis, termasuk spasi ganda, tanda hubung, atau tanda baca lainnya.
- Deklarasi Unik: Jangan mendefinisikan dua handler dengan nama yang persis sama dalam satu play. Jika kita melakukannya, hanya definisi handler terakhir yang akan dibaca oleh Ansible, sedangkan definisi sebelumnya akan ditimpa (overwritten).
Mari kita lihat contoh penulisan yang rentan mengalami error pencocokan dan bagaimana cara memperbaikinya:
# SALAH: Kesalahan penulisan nama yang menyebabkan handler tidak pernah terpicu
tasks:
- name: Mengonfigurasi parameter sysctl kernel
sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
notify: reload sysctl # ✗ Typo case-sensitive
handlers:
- name: Reload Sysctl # ✗ Menggunakan huruf kapital di awal kata
command: sysctl -p
# BENAR: Nama notifikasi dan nama handler cocok secara sempurna
tasks:
- name: Mengonfigurasi parameter sysctl kernel
sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
notify: Reload Sysctl # ✓ Cocok dengan nama handler di bawah
handlers:
- name: Reload Sysctl # ✓ Cocok dengan notifikasi di atas
command: sysctl -p
Strategi Penanganan Kegagalan: Mengamankan Eksekusi Handler #
Siklus hidup handler yang ditangguhkan hingga akhir play membawa satu konsekuensi logis: jika playbook mengalami kegagalan di tengah jalan sebelum mencapai fase eksekusi handler, seluruh antrian handler untuk host yang gagal tersebut akan dibatalkan secara otomatis.
Perilaku default ini dirancang untuk keselamatan sistem. Asumsinya adalah jika sebuah task utama gagal (misalnya instalasi dependensi aplikasi tidak berhasil), maka sistem berada dalam kondisi tidak stabil. Memulai ulang layanan aplikasi dengan konfigurasi baru pada sistem yang setengah jadi bisa memperburuk kerusakan atau menyebabkan kegagalan booting sistem secara fatal.
Namun, dalam skenario tertentu, perilaku default ini justru tidak kita inginkan.
Masalah Layanan yang Menggantung #
Bayangkan kita sedang memperbarui file konfigurasi nginx dan juga melakukan beberapa tugas pemeliharaan file statis di direktori HTML. Konfigurasi nginx berhasil diperbarui, memicu notifikasi Restart Nginx. Namun, tugas pemeliharaan file statis berikutnya gagal karena kehabisan ruang penyimpanan di disk. Playbook langsung terhenti secara mendadak.
Karena playbook gagal sebelum mencapai akhir play, handler Restart Nginx tidak pernah dijalankan. Akibatnya, server nginx tetap berjalan menggunakan konfigurasi lama yang sudah usang di memori, sementara file konfigurasi baru di media penyimpanan sudah berubah. Kondisi tidak sinkron antara memori dengan disk ini adalah bom waktu yang sewaktu-waktu dapat meledak ketika server mengalami restart mendadak di masa mendatang.
Solusi 1: Menerapkan force_handlers dalam Playbook
#
Untuk mengatasi masalah di atas, kita bisa memberitahu Ansible agar tetap menjalankan handler yang telah berhasil dimasukkan ke dalam antrian, meskipun ada task utama berikutnya yang mengalami kegagalan. Kita bisa mengaktifkan opsi ini di tingkat play dengan menuliskan force_handlers: true:
# BENAR: Memaksa jalannya handler meskipun ada kegagalan task utama
- name: Playbook Pembaruan Aplikasi dengan Proteksi Handler
hosts: appservers
force_handlers: true # ✓ Memastikan handler tetap berjalan jika statusnya sudah di-notify
tasks:
- name: Memperbarui file konfigurasi database.yml
template:
src: database.yml.j2
dest: /var/www/app/config/database.yml
notify: Restart Aplikasi Rails
- name: Mengunduh aset statis (Tugas ini berpotensi gagal)
get_url:
url: http://internal.server/assets.tar.gz
dest: /var/www/app/assets.tar.gz
# Jika tugas ini gagal, handler "Restart Aplikasi Rails" tetap akan dijalankan
# untuk menerapkan perubahan konfigurasi database.yml yang sudah sukses disalin.
handlers:
- name: Restart Aplikasi Rails
systemd:
name: rails-app
state: restarted
Solusi 2: Menggunakan Parameter CLI --force-handlers
#
Jika kita tidak ingin menuliskan opsi tersebut secara permanen di dalam playbook, kita bisa memaksakan perilaku yang sama secara ad-hoc saat mengeksekusi perintah di terminal menggunakan opsi --force-handlers:
ansible-playbook -i inventory/ hosts.ini site.yml --force-handlers
Solusi 3: Mengatur Default Secara Global di ansible.cfg #
Untuk konsistensi di seluruh tim developer, kita dapat mengubah perilaku default Ansible dengan menambahkan konfigurasi berikut ke dalam berkas ansible.cfg proyek kita:
[defaults]
# Mengaktifkan eksekusi handler secara paksa jika terjadi kegagalan task utama
force_handlers = True
Teknik Lanjutan: Mengontrol Eksekusi Handler secara Presisi #
Ketika kita membangun alur kerja otomatisasi yang kompleks, kita sering kali membutuhkan kontrol yang lebih presisi atas kapan dan bagaimana handler harus dijalankan. Ansible menyediakan beberapa fitur bawaan untuk kebutuhan manipulasi tingkat lanjut ini.
1. Pemicuan Ganda (Multiple Notifications) #
Satu task utama tidak terbatas hanya untuk memicu satu handler. Kita bisa memberikan daftar (list) berisi beberapa nama handler yang ingin dijalankan secara bersamaan ketika terjadi perubahan pada task tersebut.
# Mengirim notifikasi ke beberapa handler sekaligus
- name: Memperbarui Konfigurasi Keamanan SSH
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: '0600'
notify:
- Validasi Konfigurasi SSH
- Restart Layanan SSH
- Kirim Log Alert Keamanan
handlers:
- name: Validasi Konfigurasi SSH
command: sshd -t
# ✓ Melakukan pengujian sintaks konfigurasi terlebih dahulu sebelum restart dijalankan
- name: Restart Layanan SSH
systemd:
name: sshd
state: restarted
- name: Kirim Log Alert Keamanan
syslog:
facility: auth
level: info
message: "Konfigurasi SSH telah diperbarui dan dimuat ulang oleh Ansible."
2. Memaksa Eksekusi Instan dengan meta: flush_handlers
#
Seperti yang kita ketahui, perilaku bawaan handler adalah menunggu hingga seluruh task utama selesai. Namun, bagaimana jika task berikutnya dalam playbook kita sangat bergantung pada status baru dari layanan yang di-notify?
Sebagai contoh, kita mengubah konfigurasi PostgreSQL untuk mengizinkan koneksi baru dari luar. Task berikutnya adalah membuat database dan user baru menggunakan modul postgresql_db. Modul postgresql_db memerlukan koneksi aktif ke PostgreSQL untuk menjalankan query. Jika kita menunggu PostgreSQL restart di akhir play, maka task pembuatan database akan langsung gagal karena PostgreSQL masih berjalan dengan konfigurasi lama yang menolak koneksi eksternal.
Untuk memecahkan masalah dependensi waktu ini, kita bisa menggunakan instruksi meta khusus bernama meta: flush_handlers. Instruksi ini menginstruksikan Ansible untuk menghentikan sementara jalannya tugas utama, mengeksekusi semua handler yang saat itu sedang berada dalam antrian, dan setelah selesai, melanjutkan kembali sisa task utama yang tertunda.
# BENAR: Menggunakan flush_handlers untuk menyelesaikan antrian handler segera
- name: Konfigurasi Database dengan Dependensi Urutan
hosts: dbservers
tasks:
- name: Menyalin konfigurasi postgresql.conf
template:
src: postgresql.conf.j2
dest: /var/lib/pgsql/data/postgresql.conf
notify: Restart PostgreSQL
- name: Menyalin konfigurasi otentikasi pg_hba.conf
template:
src: pg_hba.conf.j2
dest: /var/lib/pgsql/data/pg_hba.conf
notify: Restart PostgreSQL
# Memaksa eksekusi restart PostgreSQL saat ini juga
- name: Jalankan proses restart database segera
meta: flush_handlers
# ✓ Semua handler yang di-notify sebelumnya (Restart PostgreSQL) dijalankan di titik ini.
- name: Membuat database aplikasi utama
postgresql_db:
name: production_db
state: present
# ✓ Task ini sekarang dapat berjalan dengan sukses karena PostgreSQL sudah aktif menggunakan konfigurasi baru.
handlers:
- name: Restart PostgreSQL
systemd:
name: postgresql
state: restarted
[!WARNING] Gunakan
meta: flush_handlersdengan sangat hati-hati. Jika playbook kita memiliki beberapa play terpisah atau memanfaatkan pemrosesan paralel yang agresif, melakukan pembersihan antrian handler secara manual di tengah jalan dapat merusak pola alur kerja yang sudah dirancang untuk berjalan aman di akhir play. Pastikan tidak ada konflik dependensi dengan host lain yang proses eksekusi task-nya berjalan lebih lambat.
Manajemen Handler di dalam Roles #
Saat kita mulai merancang playbook menggunakan arsitektur modular berbasis Role, lokasi penyimpanan handler harus mengikuti struktur direktori standar Ansible.
Setiap role memiliki sub-direktori khusus bernama handlers. Ansible akan mencari file bernama main.yml di dalam direktori tersebut untuk memuat definisi handler yang dimiliki oleh role tersebut secara otomatis.
Struktur folder role yang bersih akan terlihat seperti ini:
roles/
├── webserver/
│ ├── tasks/
│ │ └── main.yml # Berisi task utama yang menggunakan 'notify'
│ ├── handlers/
│ │ └── main.yml # Berisi definisi handler untuk role webserver
│ └── templates/
│ └── nginx.conf.j2
Di dalam roles/webserver/handlers/main.yml, kita mendefinisikan handler tanpa pembungkus tag handlers: di tingkat teratas. Kita langsung menuliskannya sebagai list YAML biasa:
# roles/webserver/handlers/main.yml
---
- name: Restart Nginx Webserver
systemd:
name: nginx
state: restarted
- name: Reload Nginx Webserver
systemd:
name: nginx
state: reloaded
Cakupan Aksesibilitas (Scope of Visibility) #
Secara default, handler yang didefinisikan di dalam suatu role bersifat global. Ini berarti task yang berada di luar role tersebut, atau task dari role lain yang disertakan dalam playbook yang sama, dapat memanggil handler milik role webserver jika nama handlernya dirujuk dengan tepat.
Namun, untuk menjaga modularitas dan mencegah kebingungan namespace, sangat disarankan untuk menjaga penamaan handler tetap unik dan mencerminkan role asalnya (seperti menyertakan nama role sebagai prefix: webserver | Restart Nginx).
Anti-Pattern Umum dan Solusi Nyata #
Berikut adalah kompilasi kesalahan umum yang sering ditemui saat mengimplementasikan handler dalam proyek Ansible beserta solusi terbaik untuk memperbaikinya.
1. Menggunakan Perintah Shell Mentah untuk Memulai Ulang Layanan #
Banyak administrator sistem yang terbiasa menggunakan command line mentah mencoba menuliskan perintah reboot atau service restart menggunakan modul shell atau command di dalam handler. Ini adalah kebiasaan buruk yang meniadakan kemampuan deteksi error bawaan dari modul layanan Ansible.
# ANTI-PATTERN: Menggunakan shell mentah untuk restart layanan
handlers:
- name: Restart Apache
shell: systemctl restart httpd
# ✗ Kelemahan: Tidak memiliki validasi status, tidak cross-platform,
# dan mempersulit debugging jika systemd gagal merestart service.
# BENAR: Memanfaatkan modul systemd atau service resmi
handlers:
- name: Restart Apache
systemd:
name: httpd
state: restarted
# ✓ Kelebihan: Menggunakan API sistem operasi secara native, mengembalikan kode error terstruktur,
# dan mendukung opsi otentikasi internal yang aman.
2. Mengabaikan Deteksi Kegagalan Sintaks pada Konfigurasi Baru #
Ketika kita melakukan modifikasi file konfigurasi aplikasi (seperti konfigurasi server web Apache atau proxy HAProxy) dan langsung memicu restart layanan, ada risiko konfigurasi baru tersebut memiliki kesalahan ketik (syntax error). Jika layanan langsung di-restart, layanan tersebut akan mati secara permanen dan memicu downtime.
# ANTI-PATTERN: Langsung restart tanpa pengujian sintaks konfigurasi
tasks:
- name: Deploy konfigurasi haproxy
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: Restart HAProxy
handlers:
- name: Restart HAProxy
systemd:
name: haproxy
state: restarted
# ✗ Jika template haproxy.cfg mengandung error sintaks,
# proses restart akan mematikan haproxy dan menghentikan seluruh lalu lintas load balancer.
Solusinya adalah dengan melakukan validasi file konfigurasi terlebih dahulu sebelum disalin menggunakan opsi validate pada modul template, atau memisahkan handler menjadi dua langkah berurutan:
# BENAR: Validasi sebelum salin dan gunakan handler berantai yang aman
tasks:
- name: Deploy konfigurasi haproxy dengan validasi bawaan
template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
validate: haproxy -c -f %s
# ✓ Validasi sintaks dijalankan pada file sementara sebelum menggantikan file aktif.
notify: Restart HAProxy
handlers:
- name: Restart HAProxy
systemd:
name: haproxy
state: restarted
Ringkasan #
- Arsitektur Event-Driven: Handler adalah task khusus yang hanya berjalan ketika dipicu oleh status
changeddari task utama yang mengirimkan sinyalnotify.- Eksekusi Akhir (Deferred): Secara default, semua handler yang terpicu dikumpulkan di dalam antrian internal dan baru dieksekusi setelah seluruh task utama selesai diproses.
- Penggabungan Notifikasi: Jika sebuah handler di-notify berkali-kali oleh berbagai task berbeda selama satu play, Ansible hanya akan mengeksekusinya satu kali di akhir play untuk efisiensi sistem.
- Isolasi per Host: Antrian handler dihitung dan dikelola secara mandiri untuk masing-masing host. Hanya host yang mengalami perubahan status (
changed) yang akan mengeksekusi handler.- Opsi Penyelamatan (Force Handlers): Kita dapat menggunakan
force_handlers: truedalam playbook atau parameter--force-handlersdi CLI untuk memaksa handler tetap berjalan meskipun terjadi kegagalan task utama.- Flush Handler: Kita dapat menggunakan instruksi
meta: flush_handlersuntuk memaksa eksekusi instan seluruh antrian handler saat itu juga sebelum melanjutkan ke task utama berikutnya.- Struktur Role: Di dalam arsitektur modular, handler disimpan dalam berkas
handlers/main.ymldi dalam direktori role yang bersangkutan tanpa deklarasi header tingkat tinggi.
← Sebelumnya: Task & Module Execution Berikutnya: Notify & Listen →