Aller au contenu

Notification Hub

Le Notification Hub est le workflow N8N qui centralise toutes les notifications de l’infrastructure. Il applique des règles intelligentes : déduplication, quiet hours, escalade, et routage multi-canal.

SourceType d’événements
Docker DIUNNouvelles versions d’images
AlertmanagerAlertes Prometheus (CPU, RAM, disk)
Health CheckStatus des services
Workflows N8NRésultats d’exécution, erreurs
CanalUsage
TelegramPrincipal, notifications interactives
ntfyBackup push mobile
DiscordOptionnel, pour équipes

ProblèmeSans hubAvec hub
Spam de notificationsChaque service notifie indépendammentPoint unique de sortie contrôlé
DoublonsMême alerte envoyée plusieurs foisDéduplication par clé + TTL
Alertes nocturnesRéveillé pour un warningQuiet hours pour non-critiques
Pas d’auditNotifications perduesHistorique complet en base
FonctionBénéfice
DéduplicationÉvite les notifications en double sur une fenêtre de temps
Quiet HoursNotifications non-critiques différées 22h-8h
Multi-canalTelegram + ntfy + Discord selon la sévérité
HistoriqueToutes les notifications stockées pour audit
EscaladeAlertes non acquittées passent en critique

┌─────────────────────────────────────────────────────────┐
│ Sources de notifications │
├─────────────────────────────────────────────────────────┤
│ Docker DIUN Alertmanager Health Check │
│ (image updates) (Prometheus) (scheduled) │
│ │ │ │ │
│ └────────────────┼───────────────────┘ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Notification Hub │ │
│ │ (workflow central) │ │
│ └───────────┬────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ Telegram ntfy Discord │
└─────────────────────────────────────────────────────────┘
Notification entrante
┌─────────────────────────────────────────────────────────┐
│ 1. Validation du payload │
│ - Type requis │
│ - Severity valide │
└───────────────────────┬─────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 2. Déduplication │
│ - Calcul clé de dédupe │
│ - Check Redis │
│ - Skip si doublon │
└───────────────────────┬─────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 3. Quiet Hours │
│ - Check heure actuelle │
│ - Différer si non-critique + nuit │
└───────────────────────┬─────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 4. Formatage │
│ - Template par type et canal │
│ - Ajout metadata contextuelles │
└───────────────────────┬─────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 5. Envoi multi-canal │
│ - Telegram (toujours) │
│ - ntfy (si critical) │
│ - Discord (si configuré) │
└───────────────────────┬─────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 6. Historisation │
│ - Sauvegarde en base │
│ - Update Redis dédupe │
└─────────────────────────────────────────────────────────┘
// Clé de déduplication
const dedupeKey = `${type}:${container}:${severity}`;
// TTL variable selon la sévérité
const ttl = {
info: 3600, // 1 heure
warning: 1800, // 30 min
critical: 300 // 5 min
};
// Vérifier si déjà envoyé
const existing = await redis.get(dedupeKey);
if (existing) {
return { skipped: true, reason: 'duplicate' };
}
// Marquer comme envoyé
await redis.set(dedupeKey, Date.now(), { EX: ttl[severity] });
HeureInfoWarningCritical
08h-22hImmédiatImmédiatImmédiat
22h-08hQueueQueueImmédiat
const isQuietHours = hour >= 22 || hour < 8;
const isCritical = severity === 'critical';
if (isQuietHours && !isCritical) {
// Différer jusqu'à 8h
return { deferred: true, sendAt: '08:00' };
}
{
"type": "update_success",
"severity": "info",
"title": "Docker Update réussi",
"message": "n8n-stack mis à jour vers 1.73.0",
"container": "n8n",
"image": "n8nio/n8n:1.73.0",
"project": "n8n-stack",
"timestamp": "2026-01-20T10:30:00.000Z",
"metadata": {
"duration_seconds": 45,
"previous_version": "1.72.0"
}
}
TypeDescriptionSévérité par défaut
update_successDocker update réussiinfo
update_failedDocker update échouécritical
update_queuedUpdate programméinfo
approval_requestDemande d’approbationwarning
alert_prometheusAlerte Prometheusvariable
container_downConteneur arrêtécritical

Depuis un workflow N8N :

// Execute Workflow node
{
"workflowId": "notification-hub",
"mode": "execute",
"inputData": {
"type": "update_success",
"severity": "info",
"title": "...",
"message": "..."
}
}

Via webhook interne :

Fenêtre de terminal
curl -X POST http://n8n:5678/webhook/notification-hub \
-H "Content-Type: application/json" \
-d '{
"type": "custom",
"severity": "info",
"title": "Test notification",
"message": "Hello from curl"
}'
ColonneTypeDescription
idUUIDIdentifiant unique
typeTextType de notification
severityTextinfo / warning / critical
payloadJSONContenu complet
channelsArrayCanaux utilisés
sent_atTimestampDate d’envoi
deferredBooleanSi différé
dedupe_keyTextClé de déduplication

LimiteImpactMitigation
Redis single-instancePerte du cache si Redis downNotification envoyée (pas de dédupe)
Pas d’escalade automatiqueAlertes non acquittées restent warningPrévu mais non implémenté
Quiet hours fixesPas de configuration par utilisateurSuffisant pour usage solo

Si besoin d’escalade automatique :

  • Tracker les alertes non acquittées
  • Après délai configurable, passer en critical
  • Optionnel : appel téléphonique via Twilio

Si volume de notifications augmente :

  • Agrégation par batch (résumé toutes les heures)
  • Digest quotidien pour les infos non urgentes
  • Filtrage par abonnement (opt-in par type)

Si équipe multi-utilisateurs :

  • Configuration quiet hours par utilisateur
  • Routage vers le bon canal selon l’utilisateur de garde
  • Gestion des acquittements partagés