Graceful Shutdown
Graceful shutdown menghentikan server menerima koneksi baru sambil membiarkan request yang sedang berjalan selesai, jadi deploy atau restart kontainer tidak pernah memotong response di tengah jalan. Deserve menangani ini secara bawaan, dan sebuah AbortSignal membuka jalan untuk memicunya dari kode.
Penanganan Sinyal Bawaan
router.serve() polos sudah mendengarkan sinyal yang dikirim process manager saat berhenti. Pada SIGINT (Ctrl+C di terminal) atau SIGTERM (yang dikirim Docker dan kebanyakan orchestrator), server berhenti menerima request baru, menguras yang masih berjalan, lalu meresolusi promise serve():
import { Router } from '@neabyte/deserve'
const router = new Router({
routesDir: './routes'
})
// Resolusi setelah pengurasan selesai
await router.serve(8000)
// Tercapai hanya setelah shutdown bersih
console.log('Server stopped')Windows mendengarkan SIGINT saja, karena SIGTERM tidak dikirim di sana. Tidak ada penyetelan yang diperlukan untuk jalur ini, jadi server dalam kontainer sudah keluar dengan bersih saat docker stop.
Memicu Shutdown Dari Kode
Meneruskan AbortSignal sebagai argumen ketiga menyerahkan pemicu ke aplikasi, yang cocok untuk test yang perlu menghentikan server atau route admin yang mengakhiri proses. Membatalkan controller menguras server dengan cara yang sama seperti sinyal:
const controller = new AbortController()
// Hentikan server setelah tiga puluh detik
setTimeout(() => controller.abort(), 30_000)
// Abort menguras, lalu serve resolusi
await router.serve(8000, '0.0.0.0', controller.signal)Menyerahkan AbortSignal mengambil alih pemicu berhenti, jadi listener bawaan SIGINT dan SIGTERM tetap mati dan controller menjadi satu-satunya cara berhenti. Saat keduanya diinginkan, sambungkan dengan membatalkan controller dari dalam listener sinyal.
Menjalankan Kerja Saat Shutdown
Pembersihan seperti menutup pool basis data atau membilas buffer berada setelah pengurasan, bukan di dalamnya. Event server:shutdown menyala setelah server selesai dikuras, jadi satu listener observability menjaga kerja shutdown tetap di satu tempat:
router.on((event) => {
// Berjalan setelah pengurasan selesai
if (event.kind === 'server:shutdown') {
console.log('Closing resources')
}
})
await router.serve(8000)Event pasangannya server:listening menyala saat server mengikat port, jadi kait startup dan shutdown berdampingan di bus yang sama.
Arti Pengurasan Bagi Sebuah Request
Request yang sedang berjalan saat pengurasan mulai akan tuntas sampai selesai, dan response-nya tetap terkirim. Koneksi yang tiba setelah pengurasan dimulai ditolak, karena listener sudah berhenti menerima. Response berumur panjang adalah satu hal yang perlu diperhatikan, karena stream atau WebSocket yang terbuka menahan pengurasan sampai koneksi itu ditutup. Membatasi berapa lama satu request boleh berjalan dengan requestTimeoutMs menjaga pengurasan tidak menunggu selamanya pada handler yang lambat.