Skip to content

Deployment notifications

A good deployment is three events: “started”, “finished”, “smoke tests passed”. If any stage doesn’t appear within a reasonable time — something is stuck.

#!/usr/bin/env bash
set -eu
set -a; source /etc/notifly.env; set +a
SVC="${1:?service name}"
TAG="${2:?image tag}"
HOST=$(hostname -s)
START=$(date +%s)
notify() {
local title="$1" msg="$2" prio="${3:-5}"
curl -s --max-time 5 \
"$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg t "$title" --arg m "$msg" --argjson p "$prio" \
'{title:$t, message:$m, priority:$p}')" >/dev/null
}
trap 'notify "❌ Deploy $SVC FAILED" "Tag: $TAG, host: $HOST, line: $LINENO" 9' ERR
notify "🚀 Deploy $SVC started" "Tag: $TAG$HOST" 5
docker pull "myrepo/$SVC:$TAG"
docker stop "$SVC" || true
docker rm "$SVC" || true
docker run -d --name "$SVC" --restart unless-stopped \
-p 8080:8080 "myrepo/$SVC:$TAG"
# smoke test
sleep 5
if curl -fs --max-time 5 http://localhost:8080/health >/dev/null; then
DUR=$(( $(date +%s) - START ))
notify "✅ Deploy $SVC OK" "Tag: $TAG, ${DUR}s, smoke OK" 4
else
notify "❌ Deploy $SVC: smoke-test failed" \
"Tag: $TAG, host: $HOST. /health не отвечает." 9
exit 1
fi

Usage:

Окно терминала
./deploy.sh api 1.42.0

After kubectl rollout:

Окно терминала
SVC="api"
NS="prod"
TAG="1.42.0"
kubectl -n "$NS" set image deployment/"$SVC" "$SVC=myrepo/$SVC:$TAG"
if kubectl -n "$NS" rollout status deployment/"$SVC" --timeout=5m; then
notify "✅ k8s rollout $SVC=$TAG OK" "ns=$NS" 4
else
notify "❌ k8s rollout $SVC=$TAG FAILED" "ns=$NS — авто-rollback?" 9
kubectl -n "$NS" rollout undo deployment/"$SVC"
fi

They have webhooks for deploy events. The simplest way is to run a thin proxy endpoint on your side that accepts the webhook and sends it to Notifly:

/api/deploy-hook
export default async function (req, res) {
const {state, name, deploy_url} = req.body || {};
const ok = state === 'ready' || state === 'success';
await fetch(`${process.env.NOTIFLY_URL}/message?token=${process.env.NOTIFLY_TOKEN}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
title: (ok ? '' : '') + ` ${name}: ${state}`,
message: `URL: ${deploy_url || '-'}`,
priority: ok ? 4 : 9,
}),
});
res.status(204).end();
}

In Vercel/Netlify settings add the webhook URL pointing to this endpoint.

Don’t trust only the healthcheck — add a “business check”:

Окно терминала
RESP=$(curl -s -o /dev/null -w "%{http_code}" \
-H "X-Test: 1" \
https://api.example.com/v1/users/me)
[ "$RESP" = "401" ] && notify "✅ Smoke OK ($RESP)" "/users/me требует auth — норм" 3 || \
notify "❌ Smoke FAIL ($RESP)" "/users/me ответил неожиданным кодом" 9
  • You can see the flow. Start-to-end, duration of each stage.
  • Smoke test is built into the notification — if you don’t get the ”✅”, something is stuck.
  • A canary for PaaS: if there hasn’t been a single ready in a week, something’s wrong with CI or with connectivity.
  • Send the diff of commits between deployments (git log $OLD..$NEW --oneline).
  • Separate Notifly channels for prod / staging — different sounds and colors.
  • On rollback — send the reason: “rollback because smoke /users/me returned 500”.