Rolling releases Vercel : canary sans monitoring, mon incident
Vercel a lancé les Rolling Releases en juin 2025 : déploie progressivement une nouvelle version à 1%, 5%, 25%, 100% des utilisateurs avec rollback automatique si un seuil d'erreur est dépassé. Sur le papier, c'est la baguette magique pour dormir tranquille. En pratique, je n'avais pas de monitoring en place, et j'ai eu 2h40 d'incident invisible pendant un déploiement qui aurait dû être safe. Voici ce qui s'est passé, pourquoi le rolling release n'a pas rollback automatiquement, et la config qui aurait changé l'issue.
L'incident — 4 mars 2026, 22h47
Soutenez mon travail sur Patreon
Accès anticipé aux articles, contenu exclusif, et la satisfaction de soutenir un auteur indépendant.
Rejoindre — à partir de 3€/moisJe déploie une nouvelle version de patricehuetz.fr qui ajoute un champ view_count sur la table blog_posts. Le migration Drizzle passe. Le déploiement passe à Vercel. Je configure la rolling release : 10% pendant 30 min, puis 50% pendant 30 min, puis 100%.
Je vais me coucher. Je me réveille à 1h27. Le site est OK. Tout a l'air normal. Je regarde les logs Vercel au matin : le déploiement est à 100%. Jusque-là, parfait.
Sauf que le lendemain matin, un lecteur me ping sur Twitter : « Ton compteur de vues est coincé à 0 sur tous les articles ». Je check. Effectivement. Puis je check les logs détaillés : depuis 23h17, tous les appels à increment_view_count() retournent une 500 silencieusement. 2h40 d'incident où aucun compteur n'était mis à jour.
Pourquoi le rolling release n'a pas rollback
C'est la vraie question. Vercel Rolling Releases est censé détecter les anomalies et rollback. Pourquoi ça n'a rien fait ?
Raison 1 : pas de métrique configurée
Par défaut, Rolling Releases monitore le taux de 5xx HTTP. Mon erreur renvoyait une 500 sur une route d'API interne qui n'est appelée que par le frontend en background pour incrémenter les compteurs. Le taux de 500 global sur mon site est resté à 0,1% (les 500 sur cette API représentaient 3% des requêtes globales, sous le seuil par défaut de 5%).
Le rolling release n'a pas détecté parce que la métrique observée était trop agrégée.
Raison 2 : pas de custom health check
Vercel permet de définir un custom health check qui appelle une route à chaque déploiement et vérifie une condition métier. Je n'en avais pas configuré. Sans, Rolling Releases ne peut pas savoir que « le compteur de vues est cassé » — ce n'est pas dans ses capteurs par défaut.
Raison 3 : pas d'alerting
Même si Vercel avait détecté quelque chose, je n'avais pas configuré d'alerting sur mon email ou Slack. Il y a des warnings dans le dashboard Vercel, mais je ne les ai pas vus parce que je dormais.
La config qui aurait tout changé
Étape 1 : une route de health check métier
// app/api/health/deep/route.ts
export async function GET() {
const checks = await Promise.all([
checkDbConnection(), // Turso ping
checkBlobConnection(), // Vercel Blob ping
checkViewCountIncrement(), // ← le check qui aurait sauvé
checkApiResponseTime(),
]);
const allHealthy = checks.every(c => c.ok);
return Response.json(
{ status: allHealthy ? "healthy" : "degraded", checks },
{ status: allHealthy ? 200 : 503 }
);
}
async function checkViewCountIncrement() {
try {
const before = await db.get("test-counter").catch(() => 0);
await db.run("UPDATE counters SET value = value + 1 WHERE id = 'test-counter'");
const after = await db.get("test-counter");
return { ok: after === before + 1, name: "view_count_increment" };
} catch (e) {
return { ok: false, name: "view_count_increment", error: String(e) };
}
}Étape 2 : configurer Vercel pour utiliser ce check
Dans le dashboard Vercel → Rolling Releases → Custom Health Check : pointer vers /api/health/deep. Si la route retourne un 5xx pendant 2 minutes consécutives, rollback automatique.
Étape 3 : un alerting minimal
Ajouter un webhook Slack qui reçoit les événements Vercel « rolling release degraded » ou « rollback triggered ». Coût : 0 €, temps : 10 minutes.
# Dans les env vars du projet Vercel
VERCEL_WEBHOOK_URL=https://hooks.slack.com/services/XXXX/YYYY/ZZZZÉtape 4 : un check externe de dernier recours
En plus du health check Vercel, j'utilise maintenant un cron externe (BetterStack Uptime, 0 € free tier) qui appelle /api/health/deep toutes les 2 minutes depuis l'extérieur. Si 3 échecs consécutifs, alerte Slack + SMS.
Le bilan de l'incident
| Métrique | Valeur |
|---|---|
| Durée incident | 2h40 |
| Requêtes view_count perdues | ~180 |
| Compteurs désynchronisés | 47 articles |
| Temps de détection (via Twitter) | 9h 30 min après début |
| Temps de fix | 12 min après détection |
| Temps de reconstruction des données | 2h (recalcul depuis logs) |
Leçon principale : un rolling release sans monitoring dédié, c'est pire qu'un déploiement classique. Tu as l'illusion d'être protégé.
Ma config actuelle depuis mars
- 1.Custom health check métier sur
/api/health/deep— vérifie 8 choses critiques - 2.Rolling release avec rollback auto si health check fail 2 min consécutives
- 3.Webhook Slack sur tous les événements de rolling release (started, degraded, rolled-back, completed)
- 4.Cron externe BetterStack toutes les 2 min en backup
- 5.Runbook documenté pour chaque type d'incident (rollback manuel, restoration de données)
Coût total de cette config : 30 minutes de setup + 0 €/mois. Aurait évité 9h de perte de données.
Ce qu'il faut retenir
- 1.Un rolling release sans monitoring est pire qu'un déploiement classique — faux sentiment de sécurité.
- 2.Les métriques par défaut sont trop agrégées pour détecter les bugs métier.
- 3.Custom health check métier obligatoire pour que le rollback auto soit utile.
- 4.Alerting Slack + cron externe en backup pour dormir tranquille.
- 5.30 minutes de setup aurait évité 9h d'incident.
Pour le workflow complet de dev + déploiement avec Ralph Loop et ses garde-fous, j'ai écrit un livre dédié :
Soutenez mon travail sur Patreon
Accès anticipé aux articles, contenu exclusif, et la satisfaction de soutenir un auteur indépendant.
Rejoindre — à partir de 3€/mois