« Error 524: A timeout occurred » — ce message affiché par la page d’erreur Cloudflare orange a commencé à apparaître, de façon reproductible, chaque fois qu’une gestionnaire de boutique tentait d’exporter l’historique complet des commandes d’une boutique WooCommerce cumulant plusieurs années d’activité et plus de 80 000 commandes.
Le réflexe naturel face à ce type d’erreur est de chercher du côté du serveur d’origine : augmenter max_execution_time, vérifier les logs PHP-FPM, regarder si le processus a été tué par une limite mémoire. Rien de tout cela n’était en cause ici, et c’est précisément ce qui rendait le diagnostic initial trompeur.
Symptôme : une erreur qui n’apparaît jamais dans les logs serveur
Premier signal révélateur : les logs PHP-FPM et le journal d’erreurs WordPress ne montraient absolument rien d’anormal au moment des exports en échec. Le processus PHP continuait de tourner en arrière-plan, terminait parfois l’export avec succès (le fichier CSV apparaissait bien sur le serveur), alors même que le navigateur affichait déjà l’erreur 524 depuis longtemps.
Ce comportement est la signature caractéristique d’un timeout côté proxy plutôt que côté origine : Cloudflare, en frontal du serveur, coupe la connexion HTTP si elle ne reçoit aucun octet de réponse pendant 100 secondes, indépendamment de ce qui se passe ensuite côté serveur. Ce délai de 100 secondes est une limite fixe de l’infrastructure Cloudflare sur les offres standard, non ajustable sans passer par un plan Enterprise avec des réglages spécifiques.
Diagnostic : un export entièrement synchrone

Le code de génération de l’export, hérité d’une extension tierce, chargeait l’intégralité des commandes en une seule requête WC_Order_Query sans limite, sérialisait chaque commande en ligne CSV dans une boucle PHP unique, puis renvoyait le fichier complet en une seule réponse HTTP :
$commandes = wc_get_orders( [
'limit' => -1,
'status' => 'any',
] );
foreach ( $commandes as $commande ) {
fputcsv( $handle, formater_ligne_export( $commande ) );
}
Sur 80 000 commandes, cette boucle demandait plusieurs minutes complètes, bien au-delà des 100 secondes tolérées par Cloudflare avant la moindre octet de réponse envoyé au navigateur — puisque le fichier CSV n’était généré et streamé qu’une fois l’intégralité du traitement terminé.
Correctif : pagination et traitement par file d’attente
La solution retenue a découpé le traitement en lots de 500 commandes, orchestrés par Action Scheduler plutôt que par une requête HTTP unique et bloquante :
function planifier_export_commandes( $decalage = 0 ) {
$commandes = wc_get_orders( [
'limit' => 500,
'offset' => $decalage,
'status' => 'any',
] );
if ( empty( $commandes ) ) {
marquer_export_termine();
return;
}
foreach ( $commandes as $commande ) {
ecrire_ligne_fichier_export( $commande );
}
as_enqueue_async_action( 'export_lot_suivant', [ $decalage + 500 ] );
}
add_action( 'export_lot_suivant', 'planifier_export_commandes' );
Chaque lot s’exécute en quelques secondes, largement sous la limite de Cloudflare, et l’interface d’administration affiche une barre de progression alimentée par un compteur stocké en transient, avec un lien de téléchargement du fichier final activé uniquement une fois tous les lots traités.
Prévention pour les boutiques à fort historique
- Tout traitement susceptible de dépasser quelques dizaines de secondes doit être découpé en tâches asynchrones, indépendamment des réglages PHP eux-mêmes, dès qu’un CDN de type Cloudflare est en frontal.
- Une jauge de progression rassure l’utilisateur mieux qu’une page qui semble figée pendant plusieurs minutes, même quand le traitement synchrone fonctionnerait techniquement en local.
- Vérifier le comportement en environnement de recette sans CDN masque ce type de problème : le timeout n’apparaît qu’en production, derrière Cloudflare.
Vérifier qu’il s’agit bien d’un timeout de proxy
Pour confirmer le diagnostic avant d’engager la refonte, une requête directe vers l’IP d’origine du serveur (via un en-tête Host forcé, en contournant Cloudflare) a permis de constater que l’export aboutissait bien après plusieurs minutes côté serveur nu, confirmant que le blocage se situait exclusivement au niveau du proxy Cloudflare et non d’une limite PHP ou serveur web.
Une erreur 524 n’est jamais un problème PHP à résoudre avec
max_execution_time: c’est un signal qu’il faut sortir du modèle requête-réponse synchrone.
En résumé
Le passage d’un export synchrone monolithique à un traitement par lots via Action Scheduler a définitivement supprimé l’erreur 524, tout en offrant un bénéfice collatéral : une interruption réseau en cours d’export ne perd plus la totalité du travail déjà effectué, puisque chaque lot valide est écrit indépendamment des suivants.