Table des matières :
Définir l’alerting “temps réel” dans PrestaShop (et ses limites)
Sur PrestaShop, “temps réel” veut rarement dire WebSocket ou push serveur→client. Dans 90% des cas, ça signifie latence de notification < 60 secondes entre un événement (incident technique ou signal métier) et un message dans Slack/Discord + un email d’astreinte. Le cœur PrestaShop n’a pas d’event bus unifié ni de mécanisme de job queue natif fiable pour de la prod (à part du cron et quelques tâches ad hoc). Donc si vous implémentez un module d’alerting temps réel PrestaShop en “synchrone” (appel HTTP vers Slack/Discord pendant le checkout), vous allez dégrader la conversion et ajouter un SPOF externe.
Deux précisions utiles quand on parle de “< 60 secondes” :
Le point non négociable : découpler la production de l’événement de la livraison de la notification. Typiquement : hook PrestaShop → insertion en file (DB/Redis) → worker cron/daemon → envoi Slack/Discord/email avec retry et backoff. Ça reste “temps réel” pour l’humain (alerte actionable), sans bloquer le front. Si vous avez déjà une culture d’observabilité, considérez l’alerting comme la couche “dernier mile” au-dessus des logs/metrics/traces, pas comme un remplacement.
Pré-requis de compatibilité à annoncer clairement : l’implémentation ci-dessous vise PrestaShop 8.1+ et 9.x, avec PHP 8.1 à 8.3. En PrestaShop 9, le split legacy/Symfony continue, mais l’intégration services/DI est plus systématique (et la modernisation BO progresse). Ne partez pas du principe que votre module sera “portable” sans adaptation : la réalité, c’est que PrestaShop traîne des zones legacy qui imposent encore des hooks historiques et une gestion d’erreurs hétérogène (cf. analyse côté logs/erreurs dans l’article interne : PrestaShop monitoring d’erreurs : logs PHP, MySQL, JavaScript et alertes e-mail).
Un dernier point souvent oublié : “temps réel” implique aussi une horodatation fiable. En pratique, logguez et stockez vos timestamps en UTC (y compris created_at et available_at de la queue), puis affichez en CET/CEST côté BO si besoin. Ça évite les incohérences pendant les changements d’heure et facilite la corrélation avec les logs infra.
Choisir les signaux : événements métier vs incidents techniques (et réduire le bruit)
Un module d’alerting temps réel PrestaShop devient vite inutilisable si vous alertez “tout”. La première étape est de définir des catégories de signaux, avec un niveau de sévérité et une politique d’escalade. Côté e-commerce, les signaux métier utiles sont souvent : commande validée, paiement refusé (par PSP), rupture de stock sur top SKU, erreur d’import catalogue, saut brutal du taux d’abandon au checkout. Côté technique : HTTP 5xx, fatal PHP, DB timeouts, débit WAF qui bloque le checkout, taux d’erreur JS anormal, erreurs cron.
Dans PrestaShop, beaucoup de “signaux techniques” ne remontent pas proprement au niveau du module parce qu’ils arrivent hors du cycle hook (fatal error, OOM, segmentation fault PHP-FPM, etc.). Pour ça, l’alerting in-app n’est pas suffisant : il faut un minimum de monitoring d’infrastructure (logs PHP-FPM, Nginx/Apache, MySQL) et un plan d’incident. L’alerting Slack/Discord/email depuis PrestaShop doit donc se concentrer sur ce qu’il sait observer de façon fiable : hooks business + erreurs applicatives capturables. Pour le reste, alimentez Slack via vos outils (Prometheus/Alertmanager, Sentry, etc.) et gardez le module comme relais local.
La réduction de bruit se fait par 4 mécanismes : déduplication, rate limiting, fenêtrage (grouping sur 1–5 minutes) et seuils (alerter sur un taux, pas sur un événement). Exemple concret : sur un incident “paiement refusé”, une alerte par refus va spammer. Un pattern plus robuste : compter les refus par PSP et alerter si refus/minute dépasse un seuil, puis notifier une synthèse toutes les 5 minutes jusqu’au retour à la normale. Pour cadrer l’opérationnel, rattachez ces alertes à un plan de réponse (voir : Sécurité PrestaShop : plan de réponse à incident et containment immédiat).
Un moyen simple de rendre la discussion “actionnable” est de formaliser une matrice sévérité → canal → attente :
| Sévérité | Exemple de signal | Canal recommandé | Attente de réaction |
|---|---|---|---|
| info | Nouveau module installé, import OK | Slack/Discord (digest) | Pas d’astreinte |
| warning | Refus PSP en hausse, erreurs cron intermittentes | Slack/Discord + mail si persistant | Dans la journée / 1h |
| critical | Checkout 5xx, paiement indisponible, stock négatif sur top SKU | Slack/Discord + email d’astreinte | Immédiat (SLA) |
Mini-scénario “terrain” (fréquent en boutique FR/UE) : pendant une promo, un transporteur/relay-point renvoie des erreurs API. Le checkout échoue uniquement quand l’acheteur choisit ce mode. Sans seuil, vous alertez à chaque panier. Avec fenêtrage + seuil, vous déclenchez un warning si > 3 erreurs/2 minutes, puis critical si > 10 erreurs/2 minutes, ce qui correspond mieux à l’impact business (et évite d’“éduquer” l’équipe à ignorer Slack).
Architecture du module : hooks, file d’attente et worker “sans casser” le checkout
Sur PrestaShop 8.1+ / 9.x, une architecture pragmatique et maintenable ressemble à ça :
1) Collecte via hooks (legacy) et services (Symfony) → création d’un objet AlertEvent normalisé.
2) Enqueue dans une table dédiée (ps_alerting_queue) ou dans Redis (si dispo) → insertion transactionnelle, ultra rapide.
3) Delivery worker appelé par cron (toutes les minutes) ou daemon supervisé → envoi vers Slack/Discord/email avec retry/backoff.
Le choix DB vs Redis : la DB MySQL/MariaDB est déjà là, donc c’est souvent le meilleur compromis. Redis est plus adapté si vous avez un débit important et que vous voulez éviter la contention sur InnoDB, mais il ajoute une dépendance d’exploitation (cf. déploiement Redis : Redis PrestaShop : configurer le cache sur VPS ou serveur dédié). Dans les deux cas, imposez une idempotence par clé d’événement (dedup_key) et un TTL métier (par exemple 10 minutes), sinon vous allez re-notifier à l’infini sur retry.
Schéma minimal de file DB (exemple) :
CREATE TABLE ps_alerting_queue (
id_alerting_queue BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME NOT NULL,
available_at DATETIME NOT NULL,
attempts TINYINT UNSIGNED NOT NULL DEFAULT 0,
status ENUM('pending','processing','sent','dead') NOT NULL DEFAULT 'pending',
channel ENUM('slack','discord','email') NOT NULL,
severity ENUM('info','warning','critical') NOT NULL,
dedup_key VARCHAR(190) NULL,
payload JSON NOT NULL,
last_error TEXT NULL,
INDEX (status, available_at),
UNIQUE KEY uniq_dedup (channel, dedup_key)
) ENGINE=InnoDB;
Deux améliorations “prod” à considérer dès le départ (sans complexifier) :
FOR UPDATE SKIP LOCKED) puis de passer status=processing. Sinon, vous risquez des doubles envois (et donc des faux positifs).dead et exposez-le au BO avec un last_error explicite.Côté hooks, ciblez ceux qui donnent un vrai signal métier : actionValidateOrder (commande), actionOrderStatusPostUpdate (changement de statut), actionObjectProductUpdateAfter (modif produit), actionObjectStockAvailableUpdateAfter (stock). La liste varie selon versions/modules ; si vous n’êtes pas sûr de l’endroit où l’événement est émis, partez de la méthode hook-first et outillez-vous pour explorer les hooks dynamiques (voir : Hooks PrestaShop : rechercher et identifier les hooks dynamiques).
Pour limiter le bruit et améliorer la valeur des alertes, normalisez un AlertEvent minimal avec :
type (ex. payment.refused_spike, stock.negative_detected)severity (info/warning/critical)shop_id / shop_name (multiboutique)fingerprint (stable, lisible)context (données non sensibles : order_id, module, http_status, ps_version)Le worker : un simple script CLI dans le module, exécuté en cron, suffit. Évitez d’implémenter un long-running worker PHP si vous n’avez pas une stack serveur qui le supporte proprement (FPM n’est pas fait pour ça). Si vous êtes sur FrankenPHP workers, l’approche daemon devient viable mais vous devez mesurer la stabilité et la fuite mémoire (cf. retours terrain : FrankenPHP : stabilité des workers et compatibilité PrestaShop en pratique).
Slack et Discord : webhooks, payloads structurés, retries et rate limits
Slack et Discord sont les cibles “temps réel” les plus utiles parce que l’équipe y vit déjà. Techniquement, on parle presque toujours de webhooks entrants : vous postez un JSON vers une URL secrète. Pour la documentation officielle, voir Slack Incoming Webhooks (API docs) et Discord Webhooks (Developer Portal).
Pour un module PrestaShop, le piège est la fiabilité : les webhooks peuvent renvoyer des 429 (rate limit), des 5xx, ou des timeouts. Donc votre delivery doit gérer : (1) timeout court (2–3s), (2) retry avec backoff exponentiel (ex : 10s, 30s, 2min…), (3) dead-letter après N tentatives, (4) circuit breaker si Slack/Discord est down pour éviter d’inonder votre file. Vous n’envoyez pas “un message”, vous exécutez une stratégie de livraison.
Un détail pratique côté rate limit : sur 429, Slack/Discord renvoient généralement un en-tête Retry-After. L’approche la plus propre est de respecter cette durée (plutôt que d’appliquer votre backoff “standard”), puis de replanifier (available_at) en conséquence. C’est précisément là que la queue prend tout son sens : vous repoussez le job sans bloquer le worker et sans marteler l’API.
Un payload Slack robuste privilégie les Blocks (lisible, structuré) et inclut un contexte exploitable : shop, env, severity, fingerprint, link back-office, order_id, customer_id si besoin (attention RGPD). Exemple minimal (envoi via symfony/http-client) :
$payload = [
'text' => '[CRITICAL] Checkout 5xx spike',
'blocks' => [
[
'type' => 'section',
'text' => ['type' => 'mrkdwn', 'text' => "*CRITICAL* – Pic de 5xx au checkout\nShop: prod-1\nFingerprint: `checkout-5xx`"],
],
[
'type' => 'context',
'elements' => [
['type' => 'mrkdwn', 'text' => 'Runbook: /runbooks/checkout-5xx'],
],
],
],
];
$client->request('POST', $slackWebhookUrl, [
'json' => $payload,
'timeout' => 3.0,
]);
Discord accepte un format plus simple (content, embeds). Le point important est d’embarquer une clé de déduplication au niveau applicatif (par ex. dedup_key = sha1(type + shop + orderId + errorCode)), sinon le retry va produire des doublons visibles. Dans le module, stockez dedup_key en DB avec contrainte UNIQUE : ça transforme la répétition en no-op.
Enfin, pensez “opérations” : ajoutez systématiquement un champ env (prod/staging) et un lien BO uniquement si votre accès admin est protégé (VPN, IP allowlist, SSO). Une alerte “CRITICAL” sans point d’entrée clair (lien runbook, lien BO, commande concernée) finit rapidement ignorée, même si elle arrive en 20 secondes.
Et si vous devez intégrer ces appels à d’autres APIs (PSP, ERP, WMS), appliquez les mêmes principes de protection des clés et de limitation de débit (voir : API : sécuriser apikey, limiter le débit et renforcer la conformité).
Email d’astreinte : transport, délivrabilité, et “pager fatigue”
L’email reste le fallback universel (et parfois l’obligation contractuelle). Mais en 2026, envoyer “juste un mail” depuis un serveur e-commerce est un anti-pattern si vous n’avez pas la délivrabilité : SPF/DKIM/DMARC, réputation IP, routage. Dans un module PrestaShop d’alerting temps réel, l’email doit être pensé comme un canal d’escalade : critique uniquement, ou “si Slack/Discord échoue”. Sinon vous créez de la pager fatigue.
Checklist “minimum viable délivrabilité” (utile en PME/ETI, y compris sur hébergement FR/UE) :
p=none au démarrage (monitoring), puis durcissement progressif selon votre politique[PS][prod][CRITICAL] …) pour règles et escaladesTechniquement, ciblez symfony/mailer (disponible/compatible via Composer sur PS 8.1+ / 9.x) et branchez un transport SMTP (Postfix relais) ou API (Mailgun/Sendgrid/Postmark) selon votre politique infra. Gardez les timeouts bas et n’envoyez jamais d’email dans le thread du front-office : même contrainte que Slack. Exemple d’approche : le worker envoie un email si severity=critical et si attempts==0 (premier déclenchement) ; les suivants sont groupés (digest) toutes les 10 minutes.
La qualité des messages email est un sujet technique : sujet normalisé ([PS][prod-1][CRITICAL]), body texte (pour incident), éventuellement HTML minimal. Ajoutez toujours : (1) timestamp UTC, (2) identifiant boutique / multiboutique, (3) fingerprint/dedup, (4) “next action” et lien runbook. Dans un incident de mise à jour ratée, par exemple, un email “CRITICAL” doit pointer vers une procédure de rollback et vers vos checklists (voir : Mise à jour PrestaShop : checklist sauvegarde, pré-production et tests et Mise à jour PrestaShop ratée : diagnostiquer et réparer rapidement).
Sécurité, secrets, RGPD : ce que votre module doit refuser de faire
Un webhook Slack/Discord, c’est une clé secrète. Le stocker en clair en base (ps_configuration) est une tentation, mais c’est une mauvaise idée dès que vous avez plusieurs admins, des exports DB, ou des dumps de prod pour debug. La base PrestaShop n’est pas un coffre-fort. Si vous êtes en environnement container/Kubernetes, la bonne pratique est de sortir la config sensible dans l’environnement. La règle est connue : “An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).” (The Twelve-Factor App, Config : https://12factor.net/config). Donc : webhook URL et SMTP credentials en variables d’environnement, injectés au runtime.
Deux garde-fous concrets que votre module doit appliquer “par défaut” :
slack_channel=ops-alerts) et une empreinte partielle (ex. hash).dead + alerte admin).Si vous ne pouvez pas faire autrement (hébergement mutualisé, pas de secrets manager), minimisez les dégâts : (1) chiffrez au repos (libsodium/OpenSSL), (2) limitez la visibilité BO (masquage + permission), (3) empêchez l’export, (4) logguez l’accès admin à la page de config. En infra sérieuse, connectez-vous à un vrai gestionnaire de secrets (Vault, AWS/GCP Secrets Manager, OVHcloud OKMS/ESO) ; si vous êtes sur Kubernetes, l’External Secrets Operator est un standard (voir : External Secrets Operator : synchroniser les secrets Kubernetes avec OVHcloud OKMS).
RGPD : un message Slack/Discord, ce n’est pas un stockage interne contrôlé. Évitez de pousser des données personnelles (email client, adresse, téléphone). Préférez des identifiants internes (idorder, idcustomer) et un lien BO protégé. Et gardez en tête un point pratique : Slack/Discord ont des rétentions variables, parfois hors UE. Donc votre module doit être capable de fonctionner avec un “mode strict” : pas de PII, uniquement des métriques et des IDs.
Bon compromis opérationnel : un événement “commande” peut notifier order_id, montant TTC, devise, mode de paiement (si non sensible), mais pas le nom du client. Si un opérateur a besoin du détail, il clique vers le BO (accès authentifié), ce qui garde la donnée au bon endroit.
Tests, exploitabilité et cas d’usage : mesurer que “temps réel” reste vrai
Un module d’alerting temps réel PrestaShop ne se valide pas en local avec “ça poste dans Slack”. Ce que vous devez tester en préprod : (1) latence bout-en-bout (event → message) P50/P95, (2) taux d’échec de livraison, (3) comportement en cas de panne Slack/Discord, (4) duplication (idempotence), (5) charge DB (queue), (6) compatibilité multiboutique. Ajoutez une commande CLI alerting:send-test qui injecte un événement synthétique et vérifie les trois canaux.
Critères d’acceptation réalistes (à adapter) :
event→notify < 60 s en prod, sur une journée “normale”dead génère une notification d’administration (sinon c’est un trou noir)Pour le debug, instrumentez votre worker : logs structurés (JSON), statut de queue, temps de traitement, nombre de retries. Si vous partez sur DB queue, exposez une page BO “Queue” (liste pending/processing/dead) avec action “requeue” et “purge”, sinon vous allez finir par manipuler la DB en prod. Pour l’analyse performance et les problèmes de requêtes N+1/locks, gardez une méthodo de profiling SQL/PHP (ex : PrestaShop debug profiling : activer et analyser performances SQL et, côté PHP, un outillage de debug cohérent : Xdebug : installer et activer Xdebug 3 pour PHP CLI et web).
Astuce d’exploitation simple (et très efficace) : planifiez un test synthétique quotidien (ou hebdomadaire) qui pousse un événement info vers un canal “healthchecks-alerting”. S’il n’arrive pas, vous savez que ce n’est pas “Slack qui est calme”, mais votre pipeline qui s’est cassé (cron désactivé, DNS, TLS, conf secrets, etc.).
Cas d’usage réaliste (observé en production sur des boutiques à trafic moyen) : une régression de module de paiement fait passer le checkout de 0,3% à 6% de 5xx en 3 minutes. Sans alerting, l’équipe le découvre “au feeling” ou via support client. Avec un pipeline “hook/monitoring → queue → Slack”, l’alerte peut tomber en moins de 60 secondes, avec un fingerprint stable et un lien runbook. Le gain n’est pas théorique : sur un panier moyen à 80€ et 20 commandes/heure, 30 minutes d’incident peuvent coûter plusieurs centaines à milliers d’euros selon votre canal d’acquisition. Votre module n’empêche pas l’incident, mais il réduit drastiquement le MTTA/MTTR — à condition d’être conçu comme un système (retries, seuils, dédup), pas comme un curl().
