gem

Notifications

How notifiers behave

Every notifier runs after the backup finishes, on success and on failure alike. None of them can fail a run: a broken webhook or an unreachable host is written to stderr and the exit code still reflects the backup itself. A notification problem must never look like a backup problem.

Stdout is registered by default. Sentinel and Slack are opt-in.

Sentinel

Setting the key is the entire integration.

config.sentinel_key = ENV["BB_SENTINEL_KEY"]

After every run the gem POSTs a report to https://boringbackup.com/ping/<key>. That arrival is what keeps the monitor alive, and the body is what fills in the size, duration and per-store detail you see on the activity page.

Delivery is retried up to 3 times, with a one second then two second pause, for server errors and rate limits. Connect and read timeouts are 5 and 10 seconds. After that it gives up and warns.

The payload

{
  "version": 1,
  "status": "success",
  "error": null,
  "database": "db_production",
  "engine": {
    "name": "postgresql",
    "client": "17.2",
    "server": "17.2"
  },
  "bytes": 2214592512,
  "duration": 48.302,
  "stores": [
    {
      "store": "s3",
      "success": true,
      "key": "database/db_production/2026/07/29-03-00-04-812.dump",
      "bytes": 2214592512,
      "duration": 48.302,
      "error": null
    }
  ]
}
fieldmeaning
statussuccess, partial_success or error. Only an explicit non-success marks the run failed
enginethe dump tool's version and the server's, as each reported it. Sentinel decides what counts as a mismatch, so the rule can change without a new gem release
byteslargest byte count across stores, which is the size of the dump
durationseconds taken by the slowest store
storesone entry per destination, each with its own key, size, time and error

Sentinel stores the body verbatim and parses it defensively, so an older gem that omits a field still records a healthy ping. When a version cannot be read, the gem sends what it has and sentinel shows nothing rather than a warning, because a check that did not happen should not look like a problem. See version mismatch for how the comparison is made, and the ping API for the endpoint itself.

Pointing somewhere else

config.sentinel_host = "https://sentinel.internal"

Useful for a staging monitor or a self-hosted instance. A host without a scheme gets https, except for localhost and loopback addresses, which get http so local development works.

Slack

config.notifier(:slack) do |slack|
  slack.webhook_url = ENV["BACKUP_SLACK_WEBHOOK"]
end

Posts the result of every run to an incoming webhook, success included. This is the gem talking about what it just did.

Sentinel's Slack integration answers a different question: it alerts when a backup that should have run did not report at all. A gem that never starts cannot tell you it never started, which is the whole reason the monitor lives somewhere else. Running both is reasonable, and if you only want one, take the sentinel one.

Stdout

Registered by default, so a backup invoked from your own code or a job prints its result to the log. bb backup removes it before running, since the command already prints a nicer version of the same thing.

Turning reporting off

config.report = false

Silences every notifier, sentinel included. Worth setting in the test environment so a suite that exercises the backup path does not ping a live monitor.

Further reading