Beban operasional on-call yang tidak terdistribusi merusak retensi engineer dan meningkatkan risiko kelalaian insiden kritis di production. Beban kerja on-call harus diperlakukan sebagai beban operasional terukur (operational toil) dengan metrik objektif, bukan tugas sampingan informal. Artikel ini membahas konfigurasi teknis PagerDuty untuk on-call rotasi adil, monitoring metrik kelelahan tim, serta integrasi webhook ke sistem observabilitas internal.

Prinsip Desain Schedule On-Call Rotasi Adil

Pola rotasi mingguan tunggal 24/7 (single-tier non-stop) adalah penyebab utama burnout. Pisahkan jadwal berdasarkan jam kerja (in-hours) dan luar jam kerja (off-hours) menggunakan pola multi-layer schedule di PagerDuty atau Opsgenie.

  • Follow-the-Sun: Jika tim terdistribusi lintas zona waktu, batasi shift off-hour maksimal 12 jam per engineer.
  • Split Primary/Secondary: Pisahkan tier primary (triage dan mitigasi awal) dan secondary (eskalasi jika primary tidak merespons dalam 10 menit atau menangani insiden kedua yang overlap).
  • Off-Hour Accounting: Page di atas jam 22.00 dan sebelum 07.00 memiliki bobot disrupsi lebih tinggi daripada insiden jam kerja.

Contoh Konfigurasi Terraform Schedule Multi-Tier

Gunakan deklarasi Infrastructure as Code (IaC) untuk memastikan transparansi rotasi tim dan mencegah perubahan jadwal ad-hoc tanpa approval.

resource "pagerduty_schedule" "backend_primary" {
  name      = "Backend Primary Rotation"
  time_zone = "Asia/Jakarta"

  layer {
    name                         = "Weekly Shift Primary"
    start                        = "2024-01-01T09:00:00+07:00"
    rotation_virtual_start       = "2024-01-01T09:00:00+07:00"
    rotation_turn_of_round_value = 1
    rotation_unit                = "weeks"
    users                        = [var.engineer_a, var.engineer_b, var.engineer_c]
  }
}

resource "pagerduty_escalation_policy" "backend_ep" {
  name      = "Backend Service Escalation Policy"
  num_loops = 2

  rule {
    escalation_delay_in_minutes = 10
    target {
      type = "schedule_reference"
      id   = pagerduty_schedule.backend_primary.id
    }
  }

  rule {
    escalation_delay_in_minutes = 15
    target {
      type = "schedule_reference"
      id   = pagerduty_schedule.backend_secondary.id
    }
  }
}

Metrik Vital: Deteksi Alert Fatigue dan Disrupsi

Evaluasi kesehatan sistem dan beban tim melalui 4 metrik spesifik yang ditarik dari PagerDuty Analytics API:

  1. Off-Hour Paging Frequency: Jumlah interupsi high-urgency di luar jam 09.00-18.00 waktu lokal per engineer. Ambang batas sehat: < 3 interupsi per minggu per engineer.
  2. MTTA (Mean Time to Acknowledge): Peningkatan MTTA yang bertahap sering menandakan alert fatigue laten, di mana engineer menunda konfirmasi karena asumsi flapping alert.
  3. Escalation Rate: Persentase insiden yang gagal diakui primary dan jatuh ke secondary. Angka di atas 10% menandakan kelebihan beban atau miskonfigurasi notifikasi.
  4. Noise-to-Action Ratio: Rasio alert yang diselesaikan (< 5 menit) tanpa tindakan perubahan deployment/infrastruktur. Alert ini harus diturunkan ke low-urgency (Slack/ticket) atau dihapus.

Webhook Alert ke Dashboard Observabilitas Internal

Agar beban kerja transparan bagi manajemen dan tim, kirim event insiden PagerDuty ke data warehouse atau backend observabilitas (Prometheus/Grafana via intermediate receiver). Berikut contoh receiver webhook menggunakan Node.js dan Express untuk mencatat histori interupsi ke basis data internal.

const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.PD_WEBHOOK_SECRET;

function verifySignature(req) {
  const signature = req.headers['x-pagerduty-signature'];
  if (!signature) return false;
  
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');

  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

app.post('/api/pagerduty-webhook', async (req, res) => {
  if (!verifySignature(req)) {
    return res.status(401).send('Invalid signature');
  }

  const event = req.body.event;
  if (event.event_type === 'incident.triggered') {
    const incident = event.data;
    const createdAt = new Date(incident.created_at);
    const hour = createdAt.getHours(); // Local timezone
    const isOffHour = hour < 9 || hour >= 18;

    await db.operational_logs.insert({
      incident_id: incident.id,
      service_id: incident.service.id,
      urgency: incident.urgency,
      assignee: incident.assignees[0]?.summary || 'Unassigned',
      is_off_hour: isOffHour,
      created_at: createdAt
    });
  }

  return res.status(200).send('OK');
});

app.listen(3000, () => console.log('PD Collector running on port 3000'));

Checklist Audit Mingguan dan Postmortem Beban Operasional

Jalankan audit operasional setiap awal sprint berdurasi 30 menit untuk mereview minggu rotasi sebelumnya:

  • Identifikasi Top Noise Generator: Cek service yang menghasilkan lebih dari 3 false positive atau insiden berulang tanpa tindakan korektif.
  • Kompensasi Disrupsi: Berikan hak time-off-in-lieu (cuti pengganti) atau dispensasi jam kerja bagi engineer yang menangani insiden di atas jam 23.00.
  • De-eskalasi Alert Threshold: Jika disk usage 85% memicu alert off-hour namun laju pertumbuhan hanya 1% per 12 jam, ubah threshold menjadi 90% atau ubah urgency menjadi low (notifikasi email/Slack, non-pager).
  • Blokir Deployment Non-Kritis: Layanan dengan error rate tinggi harus diprioritaskan untuk reliabilitas alur deployment sebelum fitur baru dirilis.

Aturan Praktis: Jika alert tidak mewajibkan engineer bangun dari tempat tidur untuk membuka laptop dalam rentang 15 menit ke depan, alert tersebut tidak boleh berstatus High Urgency.