---
title: "แจ้งเตือนแบ็กอัปล้มเหลว: รู้ก่อนถึงวันต้องกู้คืน"
description: "แบ็กอัปพังเงียบ ๆ ได้หลายสัปดาห์ จับข้อผิดพลาดของ restic และ borg สแนปช็อตเก่า และงานที่ไม่รัน แล้วให้โทรศัพท์ดังเมื่อแบ็กอัปพัง พร้อมสคริปต์คัดลอกใช้ได้"
date: 2026-10-09
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - การเฝ้าระวังแบ็กอัป
  - restic
  - borg
  - แจ้งเตือนความล้มเหลว
  - แจ้งเตือนแบบโทรเข้า
  - เว็บฮุก
---

# แจ้งเตือนแบ็กอัปล้มเหลว: รู้ก่อนถึงวันต้องกู้คืน

คนส่วนใหญ่รู้ว่าแบ็กอัปของตัวเองพังก็ตอนที่ต้องใช้มันนี่แหละ งานจบด้วยข้อผิดพลาดตั้งแต่สามสัปดาห์ก่อน ไม่มีใครเปิดอ่านล็อก และสแนปช็อตล่าสุดก็เก่ากว่าความผิดพลาดที่คุณกำลังจะย้อนกลับ

ทางแก้ไม่ใช่เครื่องมือแบ็กอัปที่ดีกว่า แต่คือการทำให้ปัญหาของแบ็กอัปไปถึงมนุษย์ภายในชั่วโมงเดียวกับที่มันเกิด คู่มือนี้แสดงวิธีทำกับ restic และ borg (รวมถึงทุกอย่างที่รันจากเชลล์) ครอบคลุมสามแบบที่แบ็กอัปล้มเหลวจริง ๆ พร้อมสคริปต์ที่คัดลอกไปใช้ได้ ขั้นสุดท้ายส่งการแจ้งเตือนไปที่โทรศัพท์ของคุณผ่าน [Echobell](/th) เพื่อให้แบ็กอัปที่พังทำให้โทรศัพท์ดัง ไม่ใช่นอนอยู่ในกล่องอีเมล

## สามแบบที่แบ็กอัปล้มเหลว

ความผิดพลาดที่พบบ่อยที่สุดคือเฝ้าแค่แบบแรกแบบเดียว

1. **รันแล้วล้มเหลว** รีโพซิทอรีถูกล็อก ดิสก์เต็ม รหัสผ่านผิด เครือข่ายหลุด เครื่องมือจบด้วยโค้ดที่ไม่ใช่ศูนย์
2. **รันแล้วสำเร็จครึ่งเดียว** restic จบด้วยโค้ด `3` เมื่อสร้างสแนปช็อตได้แต่อ่านบางไฟล์ไม่ได้ ส่วน borg จบด้วย `1` เมื่อมีคำเตือน ทั้งสองอย่างปัดทิ้งได้ง่าย และทั้งคู่อาจซ่อนปัญหาสิทธิ์ที่ข้ามไดเรกทอรีสำคัญที่สุดของคุณไปเงียบ ๆ
3. **ไม่เคยรันเลย** เซิร์ฟเวอร์ดับ ไทเมอร์ถูกปิด crontab ถูกเขียนทับ ไม่มีข้อผิดพลาดเพราะไม่มีโปรเซส นี่คือความล้มเหลวที่ทำให้คนเสียหายหนักที่สุด

แต่ละแบบต้องใช้ตัวตรวจจับคนละอย่าง เราจะสร้างครบทั้งสาม

## ขั้นที่ 1: สร้างช่องที่เรียกความสนใจคุณได้

ใน Echobell สร้างช่องชื่อ `backups` และตั้งประเภทการแจ้งเตือนเป็น **โทรเข้า (Calling)** สำหรับงานที่สำคัญ แล้วคัดลอก URL เว็บฮุกของช่อง:

```
https://hook.echobell.one/t/<channel-token>
```

ใส่เทมเพลตที่อ่านเข้าใจแม้ตอนยังงัวเงีย โดยใช้ฟิลด์ที่เราจะส่งไปด้านล่าง:

```
หัวเรื่อง: Backup {{status}} on {{host}}
เนื้อหา: {{job}}: {{detail}}
```

ดูไวยากรณ์ได้ใน[คู่มืออ้างอิงเทมเพลต](/th/docs/template)

## ขั้นที่ 2: จับความล้มเหลวด้วยสคริปต์ห่อคำสั่ง

สคริปต์เล็ก ๆ ที่ห่อคำสั่งไว้จะแปลงโค้ดที่จบการทำงานเป็นการแจ้งเตือน บันทึกเป็น `/usr/local/bin/backup-run`:

```bash
#!/usr/bin/env bash
set -uo pipefail

HOOK="https://hook.echobell.one/t/<channel-token>"
JOB="nightly-restic"

alert() {
  curl -fsS -m 10 -X POST "$HOOK" \
    -H "Content-Type: application/json" \
    -d "{\"job\":\"$JOB\",\"host\":\"$(hostname)\",\"status\":\"$1\",\"detail\":\"$2\"}" || true
}

restic backup /srv /etc --exclude-caches
code=$?

case $code in
  0)  ;;                                   # สำเร็จ: เงียบไว้
  3)  alert "incomplete" "Snapshot saved, but some files were unreadable" ;;
  11) alert "locked" "Repository is locked by another process" ;;
  12) alert "auth-failed" "Wrong repository password" ;;
  *)  alert "failed" "restic exited with code $code" ;;
esac

exit $code
```

รายละเอียดที่สำคัญ:

- จงใจ **ไม่ใช้** `set -e` เพื่อให้สคริปต์ยังไปถึงการแจ้งเตือนได้หลัง restic ล้มเหลว
- `|| true` หลัง `curl` ทำให้เว็บฮุกที่เข้าถึงไม่ได้ไม่บดบังโค้ดจบการทำงานที่แท้จริง
- `-m 10` ป้องกันการเรียกเครือข่ายที่ค้างไม่ให้บล็อกรอบรันถัดไป

โค้ดจบการทำงานของ restic ที่ใช้ข้างบนมีระบุไว้ในคู่มือของ restic: `0` สำเร็จ, `1` ข้อผิดพลาดร้ายแรง, `3` สร้างสแนปช็อตแล้วแต่อ่านบางไฟล์ต้นทางไม่ได้, `10` ไม่มีรีโพซิทอรี, `11` ล็อกไม่สำเร็จ, `12` รหัสผ่านผิด ตรวจสอบกับ `restic version` บนเครื่องของคุณเอง เพราะมีการเพิ่มโค้ดเข้ามาเรื่อย ๆ

### borg และ borgmatic

borg คืนค่า `0` เมื่อสำเร็จ `1` เมื่อมีคำเตือน และ `2` ขึ้นไปเมื่อเกิดข้อผิดพลาด ไฟล์ที่เปลี่ยนระหว่างแบ็กอัปทำให้ได้ `1` ซึ่งเป็นเรื่องปกติของไดเรกทอรีล็อก วิธีที่นิยมคือโทรเรียกเฉพาะ `2` ขึ้นไป และส่งการแจ้งเตือนแบบเงียบสำหรับ `1`:

```bash
borg create --stats ::'{hostname}-{now}' /srv /etc
code=$?
if [ "$code" -ge 2 ]; then
  alert "failed" "borg exited with code $code"
elif [ "$code" -eq 1 ]; then
  alert "warning" "borg finished with warnings"
fi
```

ถ้าใช้ borgmatic ฮุก `on_error` จะรันคำสั่งเมื่อ borgmatic เองเจอข้อผิดพลาด ซึ่งเป็นที่เหมาะสำหรับ `curl` ตัวเดิม แต่ให้ระวังข้อจำกัดที่เอกสารของ borgmatic บอกไว้เอง: ถ้า borgmatic ไม่ได้รันเลย `on_error` ก็ไม่ทำงาน นั่นคือความล้มเหลวแบบที่สาม ซึ่งต้องใช้ขั้นที่ 3

## ขั้นที่ 3: จับแบ็กอัปที่ไม่เคยรัน

สคริปต์ห่อคำสั่งรายงานได้เฉพาะรอบที่รันจริง การจับความเงียบต้องกลับตรรกะ: แบ็กอัปส่งสัญญาณไปที่ตัวเฝ้าระวังเมื่อ **สำเร็จ** และตัวเฝ้าระวังจะแจ้งเตือนคุณเมื่อสัญญาณ **มาช้า** เรียกว่า dead man's switch

[Healthchecks.io](https://healthchecks.io) (แบบโฮสต์หรือติดตั้งเอง) ทำสิ่งนี้ได้พอดี:

1. สร้างเช็กด้วยตารางเวลา `0 3 * * *` และเวลาผ่อนผันหนึ่งหรือสองชั่วโมง
2. ใส่ ping ของเช็กนั้นไว้ท้ายงาน เพื่อให้ยิงเฉพาะเมื่อสำเร็จ
3. ในส่วน integrations ของเช็ก เพิ่ม **Webhook** ที่ชี้ไปที่ URL ช่อง Echobell ของคุณ

ping อยู่ท้ายสคริปต์ห่อคำสั่ง:

```bash
# ใน backup-run วางไว้ก่อน `exit $code` บรรทัดสุดท้าย ping เฉพาะเมื่อสำเร็จ
if [ $code -eq 0 ]; then
  curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi
```

Healthchecks ยังรองรับ ping แบบ `/start` และ `/fail` และรับโค้ดจบการทำงานใน URL ได้ ดังนั้นเช็กเดียวจึงจับงานที่ค้างได้ด้วย ผลลัพธ์คือ เซิร์ฟเวอร์ที่ดับ ไทเมอร์ที่ถูกปิด และบรรทัด crontab ที่ถูกลบ ล้วนจบแบบเดียวกัน คือโทรศัพท์ดัง สำหรับรูปแบบทั่วไปและตัวเฝ้าระวังอื่น ๆ ดู[การแจ้งเตือนเมื่อ cron job ล้มเหลว](/th/blog/cron-job-failure-alerts)

## ขั้นที่ 4: ตรวจว่าแบ็กอัปใหม่และกู้คืนได้

แบ็กอัปอาจรันตามเวลา จบด้วย `0` แล้วก็ยังใช้ไม่ได้ เช่น เมื่อคุณแบ็กอัปไดเรกทอรีว่างเพราะเมานต์ล้มเหลว เพิ่มการตรวจสอบง่าย ๆ สองอย่างในงานรายวันแยกต่างหาก:

**อายุของสแนปช็อต** แจ้งเตือนถ้าสแนปช็อตล่าสุดเก่ากว่าที่คาดไว้:

```bash
latest=$(restic snapshots --latest 1 --json | jq -r '.[0].time')
age_h=$(( ( $(date +%s) - $(date -d "$latest" +%s) ) / 3600 ))
if [ "$age_h" -gt 30 ]; then
  alert "stale" "Newest snapshot is ${age_h}h old"
fi
```

**ความสมบูรณ์ของรีโพซิทอรี** `restic check` ตรวจโครงสร้างของรีโพซิทอรี รันสัปดาห์ละครั้ง สำหรับรีโพซิทอรีขนาดใหญ่ `restic check --read-data-subset=5%` สุ่มตรวจข้อมูลโดยไม่ต้องอ่านทั้งหมด แจ้งเตือนเมื่อจบด้วยโค้ดที่ไม่ใช่ศูนย์

ทั้งสองอย่างแทนการทดสอบกู้คืนจริงไม่ได้ ไตรมาสละครั้ง ลองกู้คืนไฟล์ที่ตรวจสอบได้ไปยังไดเรกทอรีชั่วคราว มันคือการทดสอบเดียวที่พิสูจน์ว่าแบ็กอัปใช้งานได้

## ขั้นที่ 5: ให้ดังเฉพาะเมื่อสำคัญ

ถ้าทุกคำเตือนโทรหาคุณ คุณจะปิดเสียงช่อง แล้วมันก็จะไม่ดังในเรื่องที่สำคัญจริง ใช้[เงื่อนไข](/th/docs/conditions)ของ Echobell แยกระดับบนช่องเดียว:

```
status == "failed" || status == "stale" || status == "auth-failed"
```

ส่ง `incomplete` และ `warning` ไปยังช่องที่สอง แบบ **สำคัญตามเวลา (Time Sensitive)** หรือแบบปกติ เพื่อให้ขึ้นบนหน้าจอล็อกโดยไม่ส่งเสียงเรียก เพิ่มช่วงเวลาได้ถ้าต้องการให้ความล้มเหลวช่วงกลางวันเงียบ โดยใช้ตัวแปร UTC ที่อธิบายไว้ในคู่มืออ้างอิงเงื่อนไข

## คำถามที่พบบ่อย

### จะรับแจ้งเตือนเมื่อแบ็กอัปล้มเหลวได้อย่างไร

ห่อคำสั่งแบ็กอัป อ่านโค้ดจบการทำงาน และส่งเว็บฮุกเมื่อได้โค้ดที่ไม่ใช่ศูนย์ แล้วเพิ่ม dead man's switch อย่าง Healthchecks.io เพื่อให้รู้เรื่องรอบที่ไม่เคยเริ่มด้วย

### ควรแจ้งเตือนโค้ดจบการทำงานใดของ restic

แจ้งเตือนแบบดังสำหรับ `1`, `10`, `11` และ `12` ซึ่งหมายถึงความล้มเหลวจริง ส่วน `3` (สร้างสแนปช็อตแล้วแต่อ่านบางไฟล์ไม่ได้) ให้ถือเป็นคำเตือนที่ต้องตรวจสอบ เพราะอาจซ่อนปัญหาสิทธิ์

### จะรู้ได้อย่างไรว่าแบ็กอัปหยุดรันไปเงียบ ๆ

ใช้ heartbeat: งานส่ง ping ไปที่ตัวเฝ้าระวังเมื่อสำเร็จ และตัวเฝ้าระวังแจ้งเตือนเมื่อ ping มาช้า ฮุกข้อผิดพลาดจับกรณีนี้ไม่ได้ เพราะไม่มีอะไรรันขึ้นมาเพื่อให้เกิดข้อผิดพลาด

### โค้ดจบการทำงานที่สำเร็จพอให้เชื่อใจแบ็กอัปไหม

ไม่พอ มันบอกแค่ว่าเครื่องมือทำงานเสร็จ ไม่ได้บอกว่าข้อมูลครบหรือกู้คืนได้ ตรวจอายุสแนปช็อต รันการตรวจความสมบูรณ์เป็นระยะ และทดสอบกู้คืนสม่ำเสมอ

### รับสายโทรเข้าแทนอีเมลได้ไหม

ได้ อีเมลพลาดได้ง่าย ช่องแบบโทรเข้าใน Echobell ทำงานเหมือนสายเรียกเข้าและทะลุโหมดโฟกัสของ iOS ได้ ดังนั้นแบ็กอัปที่ล้มเหลวตอนตีสามจะไม่ถูกมองข้าม

## สรุป

ตัวตรวจจับสามอย่างครอบคลุมความล้มเหลวสามแบบ: สคริปต์ห่อคำสั่งที่ดูโค้ดจบการทำงานสำหรับรอบที่ล้มเหลว การตรวจความสดใหม่สำหรับรอบที่สำเร็จแต่ใช้ไม่ได้ และ heartbeat สำหรับรอบที่ไม่เคยเกิดขึ้น ส่งทั้งหมดไปที่ช่องแบบโทรเข้า เก็บคำเตือนไว้ในช่องที่เงียบกว่า แล้วแบ็กอัปที่พังจะกลายเป็นงานแก้ห้านาที ไม่ใช่สุดสัปดาห์ที่สูญเปล่า

[ดาวน์โหลด Echobell สำหรับ iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-backup-failure-alerts-th&mt=8) หรือ [รับบน Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid) สร้างช่อง `backups` แล้วรันสคริปต์ห่อคำสั่งสักครั้งด้วยรหัสผ่านที่ใส่ผิดไว้ เพื่อฟังเสียงมันดัง

## บทความที่เกี่ยวข้อง

- [แจ้งเตือนเมื่อ cron job ล้มเหลว](/th/blog/cron-job-failure-alerts)
- [คู่มือนักพัฒนาเรื่องความล้าจากการแจ้งเตือน](/th/blog/fix-alert-fatigue-developer-guide)
- [คู่มืออ้างอิงเงื่อนไขของช่อง](/th/docs/conditions)
- [คู่มือการเชื่อมต่อเว็บฮุก](/th/docs/webhook)
- [แจ้งเตือนใบรับรอง SSL ใกล้หมดอายุ](/th/blog/ssl-certificate-expiry-alerts)
