A

Blog Post

Menghubungkan Webhook Discord dan Telegram untuk Notifikasi Deployment Otomatis

Panduan untuk membangun notifikasi deployment otomatis ke Discord dan Telegram dengan payload yang berguna, noise yang terkontrol, dan jejak audit yang tetap jelas.

5 min read
Menghubungkan Webhook Discord dan Telegram untuk Notifikasi Deployment Otomatis

TL;DR

  • Notifikasi deployment sebaiknya dikirim lewat notifier kecil yang mengurus format, deduplikasi, dan routing channel.
  • Discord dan Telegram efektif sebagai surface koordinasi, bukan sebagai source of truth audit release.
  • Payload yang berguna harus menyertakan service, environment, version, status, dan link ke pipeline atau dashboard.

Pendahuluan

Mengirim notifikasi deployment ke chat tool terdengar mudah, tetapi implementasi yang terlalu langsung biasanya cepat menjadi sumber noise. Semua build masuk ke satu channel, retry CI menciptakan spam, dan tidak ada link ke log atau release. Dalam kondisi itu, pesan deployment berhenti menjadi sinyal operasional.

Tutorial ini membuat jalur notifikasi deployment yang sederhana tetapi cukup production-ready. Targetnya adalah satu notifier berbasis Node.js yang menerima event deploy dari CI/CD, lalu menerjemahkannya ke Discord dan Telegram dengan format yang konsisten.

Prerequisites

  • Linux server atau runner CI yang bisa menjalankan Node.js 18+.
  • Akses ke Discord server dan Telegram bot.
  • Discord webhook URL yang sudah dibuat.
  • Telegram bot token dan chat_id.
  • Pipeline CI/CD yang bisa menjalankan script setelah deploy.
  • Secret management untuk menyimpan webhook dan token, misalnya GitHub Actions secrets atau environment file yang aman.

Problem di Production

Masalah terbesar biasanya bukan kegagalan mengirim HTTP request, tetapi kualitas event yang buruk. Semua pesan terlihat sama, environment tidak jelas, dan retry deployment mengirim tiga atau empat notifikasi untuk event yang sama. Tim akhirnya berhenti membaca channel.

Mental Model

Anggap notifikasi deployment sebagai contract operasional. Setiap pesan harus menjawab:

  1. apa yang berubah
  2. di environment mana
  3. status deploy apa
  4. ke mana operator bergerak berikutnya

Jika pesan tidak menjawab keempat hal itu, ia lebih dekat ke noise daripada notifikasi.

Konsep Utama

Notifier terpusat lebih sehat daripada webhook langsung dari banyak job

Jika tiap pipeline memanggil Discord dan Telegram langsung dengan format berbeda, kualitas sinyal akan cepat rusak. Satu notifier kecil memberi kontrol lebih baik.

Deduplikasi itu wajib

Retry network, rerun job, atau parallel deploy bisa menciptakan event ganda. Notifier harus bisa mengenali event yang sama.

Chat channel bukan audit system

Pesan chat mudah hilang di timeline. Notifikasi seharusnya selalu mengandung pointer ke pipeline, release, atau dashboard.

Concept diagram

Arsitektur / Context

Arsitektur yang dipakai:

  1. pipeline deploy mengirim payload JSON ke notifier
  2. notifier memvalidasi secret dan event shape
  3. notifier membuat dedupeKey
  4. notifier mengirim pesan ke Discord dan Telegram
  5. notifier mencatat hasil kirim ke log lokal

Pola ini memudahkan pemisahan channel berdasarkan environment, misalnya staging ke channel yang lebih tenang dan production ke channel yang lebih ketat.

Architecture flow

Practical Implementation

Step 1: Buat project notifier

mkdir -p ~/deploy-notifier
cd ~/deploy-notifier
npm init -y
npm install express

Step 2: Siapkan environment variable

cat > .env <<'EOF'
PORT=4010
NOTIFIER_SHARED_SECRET=change-me
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
TELEGRAM_BOT_TOKEN=123456:ABCDEF
TELEGRAM_CHAT_ID=-1001234567890
EOF

Jangan commit file ini ke repo.

Step 3: Buat service notifier

// server.js
import express from "express";

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

const sentEvents = new Map();

function buildMessage(payload) {
  return [
    `deploy ${payload.status}`,
    `service: ${payload.service}`,
    `env: ${payload.environment}`,
    `version: ${payload.version}`,
    `url: ${payload.url}`
  ].join("\n");
}

async function sendDiscord(message) {
  const res = await fetch(process.env.DISCORD_WEBHOOK_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ content: "```txt\n" + message + "\n```" })
  });

  if (!res.ok) {
    throw new Error(`Discord failed with status ${res.status}`);
  }
}

async function sendTelegram(message) {
  const res = await fetch(
    `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`,
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        chat_id: process.env.TELEGRAM_CHAT_ID,
        text: message
      })
    }
  );

  if (!res.ok) {
    throw new Error(`Telegram failed with status ${res.status}`);
  }
}

app.post("/notify/deploy", async (req, res) => {
  if (req.headers["x-notifier-secret"] !== process.env.NOTIFIER_SHARED_SECRET) {
    return res.status(401).json({ ok: false, error: "unauthorized" });
  }

  const payload = req.body;
  const dedupeKey = `${payload.environment}:${payload.service}:${payload.version}:${payload.status}`;

  if (sentEvents.has(dedupeKey)) {
    return res.json({ ok: true, deduped: true });
  }

  const message = buildMessage(payload);

  await Promise.all([sendDiscord(message), sendTelegram(message)]);
  sentEvents.set(dedupeKey, Date.now());

  console.log(JSON.stringify({ event: "deploy_notification_sent", dedupeKey, payload }));
  res.json({ ok: true });
});

app.listen(process.env.PORT || 4010, () => {
  console.log(`notifier listening on ${process.env.PORT || 4010}`);
});

Untuk runtime yang lebih stabil, simpan dedupe key di Redis atau database, bukan Map in-memory.

Step 4: Jalankan notifier

node --env-file=.env server.js

Jika memakai CommonJS, sesuaikan import menjadi require.

Step 5: Uji manual dengan curl

curl -X POST http://localhost:4010/notify/deploy \
  -H "Content-Type: application/json" \
  -H "x-notifier-secret: change-me" \
  -d '{
    "service": "billing-api",
    "environment": "production",
    "version": "sha-9f1ab23",
    "status": "succeeded",
    "url": "https://github.com/org/repo/actions/runs/123456"
  }'

Pastikan pesan muncul di Discord dan Telegram sebelum integrasi ke CI.

Step 6: Pasang sebagai systemd service

sudo tee /etc/systemd/system/deploy-notifier.service > /dev/null <<'EOF'
[Unit]
Description=Deployment Notifier
After=network.target

[Service]
WorkingDirectory=/home/ubuntu/deploy-notifier
EnvironmentFile=/home/ubuntu/deploy-notifier/.env
ExecStart=/usr/bin/node server.js
Restart=always
User=ubuntu

[Install]
WantedBy=multi-user.target
EOF

Aktifkan:

sudo systemctl daemon-reload
sudo systemctl enable --now deploy-notifier
sudo systemctl status deploy-notifier

Step 7: Integrasikan ke GitHub Actions

- name: Send deployment notification
  if: always()
  run: |
    STATUS="${{ job.status }}"
    curl -X POST https://notifier.example.com/notify/deploy \
      -H "Content-Type: application/json" \
      -H "x-notifier-secret: ${{ secrets.NOTIFIER_SHARED_SECRET }}" \
      -d "{
        \"service\": \"billing-api\",
        \"environment\": \"production\",
        \"version\": \"${{ github.sha }}\",
        \"status\": \"${STATUS}\",
        \"url\": \"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"
      }"

Pisahkan endpoint atau payload jika staging dan production memakai channel berbeda.

Verification

Periksa health process:

sudo systemctl status deploy-notifier
journalctl -u deploy-notifier -n 50

Uji endpoint secara manual:

curl -s http://localhost:4010/notify/deploy \
  -H "Content-Type: application/json" \
  -H "x-notifier-secret: change-me" \
  -d '{"service":"demo","environment":"staging","version":"v1","status":"failed","url":"https://example.com"}'

Sukses berarti:

  • endpoint merespons ok: true
  • pesan terkirim ke Discord dan Telegram
  • log lokal mencatat dedupeKey
  • event ganda dengan payload sama tidak mengirim pesan kedua

Studi Kasus / Masalah Nyata

Semua build masuk ke channel production

Penyebabnya biasanya tidak ada routing berdasarkan environment. Hasilnya channel kehilangan kredibilitas.

Pesan sukses muncul dua kali

Sering terjadi saat pipeline di-retry. Jika tidak ada deduplication key, noise akan menumpuk.

Troubleshooting

Discord webhook gagal

Periksa response status dari Discord. 404 biasanya berarti webhook URL salah atau sudah dihapus.

journalctl -u deploy-notifier -n 100 | grep Discord

Telegram tidak menerima pesan

Validasi bot token dan chat id:

curl "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"
curl "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates"

Unauthorized ke notifier

Pastikan header x-notifier-secret sama dengan nilai di environment notifier dan secret CI.

Production Notes

  • Simpan webhook URL dan bot token di secret manager, bukan di repo.
  • Pisahkan channel notifikasi staging dan production.
  • Tambahkan timeout, retry terbatas, dan logging terstruktur jika notifier makin penting.
  • Untuk dedupe yang persisten, pindahkan state dari memory ke Redis.
  • Pastikan notifier sendiri dimonitor; sistem notifikasi yang mati diam-diam tidak memberi nilai.

Trade-offs

  • Notifier terpusat memberi konsistensi, tetapi menambah satu service operasional baru.
  • Mengirim hanya event penting menurunkan noise, tetapi sebagian tim mungkin merasa visibilitas berkurang.
  • Deduplikasi menjaga channel tetap bersih, tetapi perlu state management yang lebih matang.

Failure Modes

  • Retry pipeline mengirim notifikasi ganda karena deduplication tidak persisten.
  • Secret webhook bocor dan endpoint dibanjiri event palsu.
  • Pesan terkirim, tetapi tidak punya link ke pipeline sehingga operator tetap harus mencari konteks manual.

Best Practices

  • Kirim hanya event deploy yang bernilai koordinasi.
  • Gunakan format pesan yang konsisten lintas channel.
  • Sertakan environment, service, version, status, dan URL.
  • Pisahkan audit release dari timeline chat.

Kesalahan Umum

  • mengirim semua event CI ke satu channel
  • tidak punya deduplication key
  • menyimpan secret di repository
  • menganggap pesan chat sebagai audit trail utama

Kesimpulan

Notifikasi deployment ke Discord dan Telegram akan berguna jika diperlakukan sebagai contract operasional yang disiplin. Dengan notifier kecil yang mengatur format, deduplikasi, dan routing, tim bisa mendapatkan sinyal release yang ringkas, konsisten, dan tetap relevan saat produksi sedang bergerak cepat.

Kalau artikel ini membantu, kamu bisa support eksperimen berikutnya.

Apresiasi di Trakteer

Keep Reading

Related posts