Délais durables : gérer le temps comme un état distribué
SchemaBridge Team · 2026-01-10 · Time, Scheduling, Orchestration
Gérer des périodes d'attente de 30 jours sans fuites de mémoire. Pourquoi `sleep()` est un anti-pattern des systèmes distribués.
Le mensonge de sleep() : pourquoi le temps est la primitive distribuée la plus difficile
Dans chaque langage de programmation, il existe une commande pour attendre. En Python, c'est time.sleep(). En Node.js, c'est setTimeout(). En Java, c'est Thread.sleep(). Ces commandes sont simples, intuitives, et pour tout ce qui dépasse quelques secondes, totalement inutiles dans un système distribué en production.
L'humble sleep() est un mensonge, car il suppose que l'environnement est stable. Il suppose que la machine exécutant le code restera vivante, que le processus ne sera pas tué par un load balancer, et que la mémoire ne sera pas récupérée par l'OS. Dans un environnement cloud moderne, ces hypothèses sont fausses. Si vous faites un sleep(24 60 60) (un jour) dans un pod Kubernetes standard, il y a 99% de chances que ce pod soit renouvelé, réduit ou redéployé avant la fin de la journée.
Lorsque le processus meurt, votre « sleep » meurt avec lui. Votre logique métier se perd dans le vide. C'est ainsi que naissent les « logiciels amnésiques » — des systèmes qui perdent la trace des essais clients, ratent les renouvellements d'abonnement, et échouent à envoyer des e-mails de suivi critiques.
La hiérarchie du temps : des secondes aux mois
Pour gérer le temps correctement, nous devons d'abord le catégoriser. Tous les délais ne se valent pas :
1. Délais transitoires (millisecondes à secondes) : il s'agit généralement de backoffs réseau ou de temps d'attente pour un verrou de base de données rapide. sleep() est parfois acceptable ici, car le risque de crash sur une fenêtre de 50ms est faible.
2. Délais courts (minutes) : c'est là que sleep() commence à échouer. Vous immobilisez un thread worker ou les ressources d'un conteneur pendant plusieurs minutes sans rien faire. C'est un gaspillage d'argent et un risque pour le pool de connexions.
3. Délais durables (heures à mois) : c'est le domaine des cycles de vie métier. Un essai gratuit de 14 jours, un délai de paiement de 30 jours, ou un calendrier de maintenance de 6 mois. Ceux-ci ne peuvent pas vivre dans le code ; ils doivent vivre dans l'infrastructure.
L'architecture des workflows endormis
Chez SchemaBridge, nous traitons le temps comme un état durable. Lorsque votre workflow atteint un « sommet de délai » (Delay Vertex), il ne bloque pas un thread. Il se sérialise sur disque et cesse d'exister en mémoire.
Le modèle de polling en base de données (faible précision, haute durabilité)
Vous stockez le « moment de réveil » dans une table de base de données. Un worker en arrière-plan (le « Poller ») interroge la table toutes les quelques secondes : SELECT * FROM timers WHERE wake_up < NOW(). C'est incroyablement durable, car un enregistrement en base peut survivre des années.
L'approche SchemaBridge
SchemaBridge utilise un moteur de planification persistant adossé à DynamoDB. Nous persistons explicitement l'intention de réveil dans notre ScheduledTaskRepository. Cela nous donne la durabilité millénaire d'un enregistrement en base de données.
Signaux et interruptions : changer le futur
Un délai durable est inutile s'il ne peut pas être annulé ou modifié. Si un utilisateur se trouve dans un sommet « attendre 3 jours le paiement », et qu'il paie au bout de 2 heures, vous devez réveiller le workflow et avancer immédiatement.
SchemaBridge prend en charge les signaux externes. Un signal est un événement envoyé VERS un workflow en cours d'exécution.
- L'attente : le workflow se trouve sur un sommet
Delayjusqu'àT + 3 joursOU jusqu'à l'arrivée d'un signalPayment_Received. - L'interruption : lorsque le signal atteint le moteur, celui-ci effectue une recherche de l'instance spécifique, réhydrate l'état, et fait transitionner le sommet immédiatement.
Nous fournissons des API explicites pour annuler ou interrompre ces tâches planifiées (par exemple, arrêter une tâche cron via la commande nuke, ou interrompre un délai spécifique via un signal webhook). Comme le délai et le signal sont tous deux gérés par le moteur, le système est immunisé contre les race conditions.
Dérive d'horloge et précision dans un maillage global
Dans un système distribué réparti sur plusieurs régions AWS, les horloges ne sont jamais parfaitement synchronisées. C'est le phénomène de dérive d'horloge (Clock Drift). Si l'horloge de la région A est en avance de 50ms sur celle de la région B, un « attendre 1 seconde » peut se comporter différemment selon l'endroit où la tâche est prise en charge.
SchemaBridge résout ce problème en utilisant une signature d'horloge logique dérivée de notre couche de métadonnées centralisée. Bien que les workers individuels utilisent leurs horloges locales pour l'exécution, l'« intention temporelle » est synchronisée globalement et enregistrée dans l'historique immuable. Peu importe que l'horloge du worker soit légèrement décalée ; ce qui compte, c'est que la durée d'exécution corresponde à votre intention métier.
Étude de cas : automatiser une campagne drip de 30 jours avec 0% d'échec
Nous avons travaillé avec une plateforme de marketing automation qui rencontrait des difficultés avec sa logique de « parcours de bienvenue ».
Le défi
Un parcours impliquait :
- Envoyer l'e-mail 1 (jour 1).
- Attendre 3 jours.
- Si l'utilisateur n'a pas cliqué, envoyer l'e-mail 2.
- Attendre 7 jours.
- Si l'utilisateur n'a pas upgradé, envoyer un code promo.
Ils utilisaient une solution maison à base de tâches cron et d'une table Postgres. Chaque semaine, pendant leur fenêtre de maintenance de base de données ou un déploiement, environ 5% des utilisateurs restaient « bloqués » dans un état d'attente et ne recevaient jamais leur e-mail suivant. Ils perdaient des milliers de dollars de revenus de conversion potentiels chaque mois.
L'approche SchemaBridge
Ils ont migré leurs parcours utilisateurs vers des workflows SchemaBridge.
1. Délais visuels : ils ont littéralement glissé un sommet « Delay » dans le graphe et l'ont réglé sur 3d et 7d.
2. Reprise durable : pendant les déploiements, les workflows se mettaient simplement en pause en base de données. Lorsque le moteur revenait en ligne, il détectait les timers ayant expiré pendant l'interruption et les reprenait immédiatement, dans le bon ordre.
3. Intégration de signaux : ils ont utilisé notre Webhook Gateway pour envoyer un signal « Click ». Si l'utilisateur cliquait sur l'e-mail, le workflow se réveillait et transitionnait instantanément vers le chemin « succès », en court-circuitant le reste du délai.
Le résultat
- Fiabilité : ils sont passés d'un taux d'échec de 5% à zéro parcours perdu.
- Bonheur des développeurs : la base de code des parcours a été réduite de 70%. Ils ont supprimé leur logique cron complexe et leur service maison de « Job Poller ».
- Impact business : les taux de conversion se sont améliorés de 12%, car les utilisateurs recevaient enfin leurs e-mails exactement au bon moment.
Comparaison : stratégies de planification existantes
| Caractéristique | setTimeout() | Tâches cron / Quartz | Délais durables SchemaBridge |
| :--- | :--- | :--- | :--- |
| Persistance | Aucune (volatile) | Manuelle (adossée à une DB) | Native (historique durable) |
| Scalabilité | Faible (liée à la RAM) | Moyenne (goulot d'étranglement DB) | Élevée (DDB shardée) |
| Annulation | Complexe (gestion manuelle) | Nettoyage manuel en DB | Signaux/interruptions visuels |
| Visibilité | Aucune | Requêtes SQL | Dashboard de progression visuel |
| Résolution | Millisecondes | Secondes/minutes | Polling géré |
Checklist d'expert pour la logique métier de longue durée
Si vous concevez un système qui attend plus de 5 minutes, suivez ces heuristiques :
1. Arrêtez le thread : ne bloquez jamais un worker pendant une attente. Votre worker doit être stateless et prêt à être tué à tout moment.
2. Externalisez l'horloge : utilisez un moteur central pour gérer le passage du temps, pas l'horloge système de la machine locale.
3. Concevez pour l'interruption : supposez toujours que l'utilisateur pourrait effectuer l'action que vous attendez avant l'expiration du délai. Utilisez des signaux pour rendre vos attentes « interruptibles ».
4. Auditez la salle d'attente : utilisez votre dashboard pour voir combien de milliers (ou de millions) de workflows sont actuellement dans un état « endormi ». C'est un indicateur important de la santé de votre activité.
5. Exploitez les décalages logiques : n'utilisez pas un horodatage fixe pour les réveils (par exemple « le 15 janvier »). Utilisez un décalage logique (par exemple +3d) pour garantir que même si la première étape du workflow est retardée, l'écart relatif reste cohérent.
Conclusion : le temps est un problème d'infrastructure
Un logiciel qui oublie est un logiciel qui échoue. En traitant le temps comme un état distribué durable de première classe, nous comblons l'écart entre les événements temps réel et le comportement humain à forte latence. Avec SchemaBridge, vous pouvez construire des parcours qui s'étendent sur des mois avec la même confiance que celle avec laquelle vous construisez une logique qui s'étend sur des millisecondes.
À l'ère de l'« Experience Economy », la capacité à gérer parfaitement le timing de vos interactions est votre plus grand avantage concurrentiel. Nous fournissons l'horloge ; vous fournissez le parcours.
Dans la partie 8, nous explorerons l'« Observability Gap » et verrons comment déboguer visuellement ces chaînes distribuées complexes, s'étalant sur plusieurs jours, sans perdre la tête dans les logs.