vendredi 25 septembre 2026

À propos

Contact

Extensions

Rejouer un webhook manqué : un journal d’événements consultable dans l’admin

Quand un événement échoue vraiment, le client ne devrait pas dépendre d'un développeur pour le relancer. Un écran d'administration simple change la donne.

Par Clément Hadrot • 2 juin 2025 • 5 min de lecture • Aucun commentaire
Rejouer un webhook manqué : un journal d'événements consultable dans l'admin

Une extension de synchronisation de stock recevait des webhooks d’un fournisseur externe à chaque changement de disponibilité produit. Certains de ces événements échouaient occasionnellement, souvent à cause d’un identifiant produit non encore synchronisé côté WordPress au moment de la réception. Sans visibilité sur ces échecs, le client s’apercevait du problème seulement en constatant, plusieurs jours plus tard, qu’un produit affichait un stock erroné, sans lien évident avec la cause réelle.

La déduplication et la robustesse technique du traitement des webhooks, sujet déjà traité par ailleurs, ne suffisent pas à elles seules : encore faut-il qu’un événement réellement échoué, pour une raison légitime et non récupérable automatiquement, puisse être rejoué sans dépendre d’une intervention développeur à chaque fois. C’est ce second problème que cet article traite : donner au client la main sur les événements en échec.

Consigner chaque événement, pas seulement les échecs

La première étape consiste à journaliser systématiquement chaque webhook reçu dans une table dédiée, avec son statut, indépendamment de son succès ou de son échec. Ce choix, plus large qu’un simple journal d’erreurs, permet ensuite de construire un écran de consultation complet plutôt qu’une liste d’incidents isolés :

global $wpdb;

$table = $wpdb->prefix . 'stock_webhooks_journal';

$sql = "CREATE TABLE $table (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    event_id VARCHAR(191) NOT NULL,
    payload LONGTEXT NOT NULL,
    statut VARCHAR(20) NOT NULL DEFAULT 'en_attente',
    message_erreur TEXT NULL,
    recu_le DATETIME NOT NULL,
    traite_le DATETIME NULL,
    PRIMARY KEY (id),
    UNIQUE KEY event_id (event_id)
) " . $wpdb->get_charset_collate() . ";";

L’écran d’administration

L’écran s’appuie sur la classe native WP_List_Table pour afficher les événements récents, avec une colonne de statut clairement visible et un filtre rapide sur les échecs. Chaque ligne en échec propose une action « Rejouer », qui déclenche à nouveau le traitement métier sans repasser par le fournisseur externe :

L'essentiel à retenir : Consigner chaque webhook reçu avec son statut, pas seulement les échecs ; Un bouton de rejeu manuel évite d'attendre une intervention technique ; Distinguer clairement un événement rejouable d'un événement définitivement clos
add_action( 'admin_post_stock_rejouer_webhook', function() {
    check_admin_referer( 'stock_rejouer_webhook' );

    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( 'Action non autorisée.' );
    }

    $id = absint( $_GET['journal_id'] ?? 0 );
    global $wpdb;

    $ligne = $wpdb->get_row(
        $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}stock_webhooks_journal WHERE id = %d", $id )
    );

    if ( ! $ligne || 'echec' !== $ligne->statut ) {
        wp_die( 'Cet événement n\'est pas rejouable.' );
    }

    $payload = json_decode( $ligne->payload, true );
    $resultat = stock_traiter_evenement_webhook( $payload );

    $wpdb->update(
        $wpdb->prefix . 'stock_webhooks_journal',
        array(
            'statut'     => $resultat ? 'traite' : 'echec',
            'traite_le'  => current_time( 'mysql' ),
        ),
        array( 'id' => $id )
    );

    wp_safe_redirect( add_query_arg( 'rejoue', $resultat ? '1' : '0', wp_get_referer() ) );
    exit;
} );

Le point important ici est la réutilisation directe de la fonction stock_traiter_evenement_webhook(), exactement la même que celle appelée lors de la réception initiale. Un rejeu manuel ne doit jamais emprunter un chemin de code différent de celui du traitement automatique, sous peine de corriger un bug d’un côté en en introduisant un autre, invisible, de l’autre.

Distinguer ce qui est rejouable de ce qui ne l’est pas

Toutes les erreurs ne se valent pas. Un événement en échec parce que le produit ciblé n’existait pas encore côté WordPress au moment de la réception redevient rejouable dès que ce produit est créé. À l’inverse, un événement concernant un produit définitivement supprimé restera en échec quel que soit le nombre de tentatives. L’écran doit refléter cette distinction, plutôt que de proposer un bouton de rejeu identique sur toutes les lignes en échec sans discernement.

  • Statut « échec récupérable » : le bouton de rejeu reste actif, une correction en amont peut suffire à débloquer la situation.
  • Statut « échec définitif » : le bouton disparaît, remplacé par un message expliquant pourquoi l’événement ne peut plus être traité.
  • Un compteur de tentatives par événement, pour repérer un événement rejoué plusieurs fois sans succès, signe probable d’un problème plus profond à corriger dans le code plutôt que par simple rejeu répété.

Autonomie du client, sans perte de traçabilité

Sur ce projet, donner au client la main sur le rejeu a réduit le délai moyen de résolution d’un événement en échec de près de deux jours à quelques minutes, le temps que le client identifie lui-même la cause probable, généralement un produit non encore synchronisé, avant de cliquer sur rejouer. La table de journal conserve malgré tout une trace complète de chaque tentative, avec la date et l’utilisateur ayant déclenché le rejeu, consultable en cas de besoin ultérieur.

Un principe qui structure désormais ce type d’écran chez nous : ne jamais laisser un client seul face à un événement en échec sans lui donner à la fois la visibilité sur la cause et un moyen d’agir directement, sans repasser par un ticket de support.

En résumé

Un journal d’événements consultable, couplé à un rejeu manuel réutilisant strictement la même logique de traitement que le flux automatique, transforme un incident habituellement invisible en une situation que le client peut résoudre lui-même en quelques clics. La distinction entre échec récupérable et échec définitif reste la pièce la plus délicate de cet écran, mais aussi celle qui évite le plus de confusion une fois en production.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi