---
title: "Alerty o awarii backupu: dowiedz się przed odtwarzaniem"
description: "Backupy psują się po cichu tygodniami. Wyłap błędy restic i borg, stare snapshoty i pominięte uruchomienia, a o awarii dowiesz się z telefonu."
date: 2026-10-09
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - monitoring backupów
  - restic
  - borg
  - alerty o awariach
  - alerty telefoniczne
  - webhooki
---

# Alerty o awarii backupu: dowiedz się, zanim będziesz musiał odtwarzać

Większość ludzi odkrywa, że backupy były zepsute, dopiero w dniu, w którym są potrzebne. Zadanie zakończyło się błędem trzy tygodnie temu, nikt nie czytał logu, a najnowszy snapshot jest starszy niż pomyłka, którą chcesz cofnąć.

Rozwiązaniem nie jest lepsze narzędzie do backupu. Chodzi o to, by problem z backupem dotarł do człowieka w tej samej godzinie, w której się pojawia. Ten przewodnik pokazuje, jak to zrobić dla restic i borg (oraz wszystkiego, co uruchamia się z powłoki), z uwzględnieniem trzech sposobów, w jakie backupy naprawdę zawodzą, wraz ze skryptami do skopiowania. Ostatni krok wysyła alert na telefon przez [Echobell](/pl), dzięki czemu zepsuty backup dzwoni, zamiast leżeć w skrzynce pocztowej.

## Trzy sposoby, w jakie backup zawodzi

Monitorowanie tylko pierwszego to najczęstszy błąd.

1. **Uruchamia się i kończy błędem.** Repozytorium zablokowane, dysk pełny, złe hasło, zerwana sieć. Narzędzie kończy działanie kodem innym niż zero.
2. **Uruchamia się i udaje się połowicznie.** restic kończy z kodem `3`, gdy snapshot powstał, ale części plików nie dało się odczytać. borg kończy z `1` przy ostrzeżeniach. Oba łatwo zbagatelizować i oba mogą ukrywać problem z uprawnieniami, który po cichu pomija Twój najważniejszy katalog.
3. **Nigdy się nie uruchamia.** Serwer był wyłączony, timer wyłączony, crontab nadpisany. Nie ma błędu, bo nie ma procesu. To awaria, która niszczy najwięcej.

Każda wymaga innego detektora, więc zbudujemy wszystkie trzy.

## Krok 1: utwórz kanał, który przyciągnie Twoją uwagę

W Echobellu utwórz kanał o nazwie `backups` i ustaw typ powiadomienia na **Połączenie** dla zadań, które się liczą. Skopiuj jego adres webhooka:

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

Nadaj mu szablony, które będą zrozumiałe nawet na pół śpiąc, z polami, które wyślemy poniżej:

```
Tytuł: Backup {{status}} na {{host}}
Treść: {{job}}: {{detail}}
```

Składnię znajdziesz w [dokumentacji szablonów](/pl/docs/template).

## Krok 2: wyłap awarie skryptem opakowującym

Mały wrapper zamienia kody wyjścia w alerty. Zapisz go jako `/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)  ;;                                   # sukces: zachowaj ciszę
  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
```

Dlaczego szczegóły mają znaczenie:

- `set -e` celowo **nie** jest użyte, dzięki czemu skrypt dociera do alertu także po awarii restic.
- `|| true` przy `curl` sprawia, że niedostępny webhook nigdy nie zamaskuje prawdziwego kodu wyjścia.
- `-m 10` zapobiega temu, by zawieszone połączenie sieciowe blokowało kolejne zaplanowane uruchomienie.

Użyte wyżej kody wyjścia restic są opisane w jego podręczniku: `0` sukces, `1` błąd krytyczny, `3` snapshot utworzony, ale część plików źródłowych nieczytelna, `10` repozytorium nie istnieje, `11` nie udało się założyć blokady, `12` złe hasło. Sprawdź je przez `restic version` na własnej maszynie, bo kody były dodawane z czasem.

### borg i borgmatic

borg zwraca `0` przy sukcesie, `1` przy ostrzeżeniach i `2` lub więcej przy błędach. Plik zmieniający się w trakcie backupu daje `1`, co jest normalne dla katalogów z logami, więc częste podejście to dzwonić tylko od `2` wzwyż, a dla `1` wysyłać ciche powiadomienie:

```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
```

Jeśli używasz borgmatic, jego hook `on_error` uruchamia polecenie, gdy sam borgmatic napotka błąd, i to naturalne miejsce na ten sam `curl`. Pamiętaj o ograniczeniu, które sama dokumentacja borgmatic wskazuje: jeśli borgmatic w ogóle się nie uruchomi, `on_error` nigdy nie zadziała. To awaria numer trzy i potrzebny jest do niej Krok 3.

## Krok 3: wyłap backup, który nigdy się nie uruchomił

Wrapper może zaraportować tylko uruchomienie, które się odbyło. Żeby wyłapać ciszę, odwróć logikę: backup wysyła ping do monitora, gdy **się powiedzie**, a monitor alarmuje, gdy ping jest **spóźniony**. To tzw. dead man's switch.

[Healthchecks.io](https://healthchecks.io) (hostowany lub własny) robi dokładnie to:

1. Utwórz check z harmonogramem `0 3 * * *` i czasem tolerancji na godzinę lub dwie.
2. Dodaj jego ping na końcu zadania, aby wysyłał się tylko po sukcesie.
3. W integracjach checku dodaj **Webhook** wskazujący na adres Twojego kanału Echobell.

Ping trafia na koniec wrappera:

```bash
# w backup-run tuż przed końcowym `exit $code`; ping tylko przy sukcesie
if [ $code -eq 0 ]; then
  curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi
```

Healthchecks obsługuje też warianty pingu `/start` i `/fail` i potrafi przyjąć kod wyjścia w adresie URL, więc jeden check wyłapie także zadania, które się zawieszają. Efekt: martwy serwer, wyłączony timer i usunięta linia crontaba dają ten sam wynik, czyli dzwoniący telefon. Ogólny wzorzec i inne monitory znajdziesz w artykule [alerty o awariach zadań cron](/pl/blog/cron-job-failure-alerts).

## Krok 4: sprawdź, czy backup jest świeży i da się go odtworzyć

Backup może uruchomić się o czasie, zakończyć kodem `0` i mimo to być bezużyteczny, na przykład gdy backupujesz pusty katalog po nieudanym zamontowaniu dysku. Dodaj dwie tanie kontrole poprawności w osobnym, codziennym zadaniu:

**Wiek snapshotu.** Alarmuj, jeśli najnowszy snapshot jest starszy, niż się spodziewasz:

```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
```

**Integralność repozytorium.** `restic check` weryfikuje strukturę repozytorium. Uruchamiaj go co tydzień; przy dużych repozytoriach `restic check --read-data-subset=5%` próbkuje dane bez czytania wszystkiego. Alarmuj przy niezerowym kodzie wyjścia.

Żadna z tych kontroli nie zastąpi prawdziwego testowego odtworzenia. Raz na kwartał odtwórz plik, który potrafisz zweryfikować, do katalogu tymczasowego. To jedyny test, który dowodzi, że backup działa.

## Krok 5: dzwoń tylko wtedy, gdy to ważne

Jeśli każde ostrzeżenie dzwoni na telefon, wyciszysz kanał, a wtedy nie zadzwoni przy tym, który ma znaczenie. Użyj [warunków](/pl/docs/conditions) Echobella, by rozdzielić poziomy na jednym kanale:

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

Wysyłaj `incomplete` i `warning` na drugi kanał, **Pilne (Time Sensitive)** lub zwykły, żeby pojawiały się na ekranie blokady bez dzwonka. Dodaj okno czasowe, jeśli chcesz, by awarie w ciągu dnia były ciche, używając zmiennych UTC opisanych w dokumentacji warunków.

## Najczęstsze pytania

### Jak dostać powiadomienie, gdy backup się nie powiedzie?

Opakuj polecenie backupu w wrapper, odczytaj jego kod wyjścia i wyślij webhook przy każdym kodzie innym niż zero. Dodaj dead man's switch, taki jak Healthchecks.io, żeby dowiadywać się też o uruchomieniach, które w ogóle nie wystartowały.

### Przy jakich kodach wyjścia restic warto alarmować?

Alarmuj głośno przy `1`, `10`, `11` i `12`, które oznaczają prawdziwą awarię. Kod `3` (snapshot utworzony, ale część plików nieczytelna) traktuj jako ostrzeżenie do zbadania, bo może ukrywać problem z uprawnieniami.

### Skąd wiem, że backup po cichu przestał się uruchamiać?

Użyj heartbeatu: zadanie wysyła ping do monitora po sukcesie, a monitor alarmuje, gdy ping jest spóźniony. Hook błędu tego nie wyłapie, bo nic się nie uruchamia, by taki błąd zgłosić.

### Czy pomyślny kod wyjścia wystarczy, by ufać backupowi?

Nie. Oznacza on, że narzędzie zakończyło pracę, a nie że dane są kompletne lub da się je odtworzyć. Sprawdzaj wiek snapshotów, regularnie uruchamiaj kontrole integralności i testuj odtwarzanie.

### Czy mogę dostać telefon zamiast e-maila?

Tak. E-mail łatwo przeoczyć. Kanał telefoniczny w Echobellu zachowuje się jak połączenie przychodzące i przebija tryb Skupienia w iOS, więc nieudany backup o 3:00 nie umknie Twojej uwadze.

## Podsumowanie

Trzy detektory pokrywają trzy tryby awarii: wrapper kodów wyjścia dla uruchomień, które się nie udają, kontrola świeżości dla tych, które kończą się sukcesem bez sensu, i heartbeat dla tych, które w ogóle nie następują. Skieruj je na kanał telefoniczny, ostrzeżenia zostaw na cichszym, a zepsuty backup stanie się pięciominutową naprawą zamiast straconego weekendu.

[Pobierz Echobella na iPhone'a](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-backup-failure-alerts-pl&mt=8) albo [weź go z Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid), utwórz kanał `backups` i uruchom wrapper raz z celowo błędnym hasłem, by usłyszeć dzwonek.

## Powiązane artykuły

- [Alerty o awariach zadań cron](/pl/blog/cron-job-failure-alerts)
- [Poradnik dla programistów o zmęczeniu alertami](/pl/blog/fix-alert-fatigue-developer-guide)
- [Dokumentacja warunków kanału](/pl/docs/conditions)
- [Przewodnik po integracji z webhookami](/pl/docs/webhook)
- [Alerty o wygasaniu certyfikatów SSL](/pl/blog/ssl-certificate-expiry-alerts)
