Construction pour les grands systèmes et les tâches d'arrière-plan de longue durée. Crédit : Ilias Chebbi sur Unsplash Il y a quelques mois, j'ai assumé le rôle qui nécessitait la construction d'infrastConstruction pour les grands systèmes et les tâches d'arrière-plan de longue durée. Crédit : Ilias Chebbi sur Unsplash Il y a quelques mois, j'ai assumé le rôle qui nécessitait la construction d'infrast

Créer un Spotify pour les sermons.

2025/12/11 21:15

Construction pour les grands systèmes et les tâches d'arrière-plan de longue durée.

Crédit : Ilias Chebbi sur Unsplash

Il y a quelques mois, j'ai assumé un rôle qui nécessitait la construction d'une infrastructure pour le streaming de médias (audio). Mais au-delà de la diffusion d'audio en morceaux streamables, il y avait des tâches de traitement média de longue durée et un vaste pipeline RAG qui s'occupait de la transcription, du transcodage, de l'intégration et des mises à jour séquentielles des médias. La construction d'un MVP avec une mentalité de production nous a fait réitérer jusqu'à ce que nous obtenions un système fluide. Notre approche a été celle où nous avons intégré les fonctionnalités et la pile sous-jacente de priorités.

Préoccupation principale :

Au cours de la construction, chaque itération est venue en réponse à un besoin immédiat et souvent "englobant". La préoccupation initiale était la mise en file d'attente des tâches, qui suffisait facilement avec Redis ; nous avons simplement lancé et oublié. Bull MQ dans le framework NEST JS nous a donné un contrôle encore meilleur sur les nouvelles tentatives, les arriérés et la file d'attente des lettres mortes. Localement et avec quelques charges utiles en production, nous avons bien géré le flux des médias. Nous avons rapidement été accablés par le poids de l'Observabilité :
Logs → Enregistrement des tâches (requêtes, réponses, erreurs).
Métriques → Combien / à quelle fréquence ces tâches s'exécutent, échouent, se terminent, etc.
Traces → Le chemin qu'une tâche a pris à travers les services (fonctions/méthodes appelées dans le chemin du flux ).

Vous pouvez résoudre certains de ces problèmes en concevant des API et en construisant un tableau de bord personnalisé pour les y connecter, mais le problème de la scalabilité suffira. Et en fait, nous avons conçu les API.

Construction pour l'Observabilité

Le défi de gérer des flux de travail backend complexes et de longue durée, où les échecs doivent être récupérables et l'état doit être durable, Inngest est devenu notre salut architectural. Il a fondamentalement recadré notre approche : chaque tâche d'arrière-plan de longue durée devient une fonction d'arrière-plan, déclenchée par un événement spécifique.

Par exemple, un événement Transcription.request déclenchera une fonction TranscribeAudio. Cette fonction pourrait contenir des étapes d'exécution pour : fetch_audio_metadata, deepgram_transcribe, parse_save_trasncription, et notify_user.

Déconstruction du Flux de Travail : La Fonction Inngest et les Étapes d'Exécution

La primitive de durabilité fondamentale est les étapes d'exécution. Une fonction d'arrière-plan est décomposée en interne en ces étapes d'exécution, chacune contenant un bloc minimal et atomique de logique.

  • Logique Atomique : Une fonction exécute votre logique métier étape par étape. Si une étape échoue, l'état de l'ensemble de l'exécution est préservé, et l'exécution peut être réessayée. Cela redémarre la fonction depuis le début. Les étapes individuelles ou les étapes d'exécution ne peuvent pas être réessayées isolément.
  • Sérialisation de Réponse : Une étape d'exécution est définie par sa réponse. Cette réponse est automatiquement sérialisée, ce qui est essentiel pour préserver les structures de données complexes ou fortement typées à travers les limites d'exécution. Les étapes d'exécution suivantes peuvent analyser de manière fiable cette réponse sérialisée, ou la logique peut être fusionnée en une seule étape pour plus d'efficacité.
  • Découplage et Planification : Au sein d'une fonction, nous pouvons mettre en file d'attente ou planifier conditionnellement de nouveaux événements dépendants, permettant des modèles complexes de fan-out/fan-in et une planification à long terme jusqu'à un an. Les erreurs et les succès à n'importe quel point peuvent être capturés, ramifiés et traités plus loin dans le flux de travail.

Abstrait de fonction Inngest :

import { inngest } from 'inngest-client';

export const createMyFunction = (dependencies) => {
return inngest.createFunction(
{
id: 'my-function',
name: 'My Example Function',
retries: 3, // retry the entire run on failure
concurrency: { limit: 5 },
onFailure: async ({ event, error, step }) => {
// handle errors here
await step.run('handle-error', async () => {
console.error('Error processing event:', error);
});
},
},
{ event: 'my/event.triggered' },
async ({ event, step }) => {
const { payload } = event.data;

// Step 1: Define first step
const step1Result = await step.run('step-1', async () => {
// logic for step 1
return `Processed ${payload}`;
});

// Step 2: Define second step
const step2Result = await step.run('step-2', async () => {
// logic for step 2
return step1Result + ' -> step 2';
});

// Step N: Continue as needed
await step.run('final-step', async () => {
// finalization logic
console.log('Finished processing:', step2Result);
});

return { success: true };
},
);
};

Le modèle événementiel d'Inngest fournit un aperçu granulaire de chaque exécution de flux de travail :

  • Traçage Complet des Événements : Chaque exécution de fonction mise en file d'attente est enregistrée par rapport à son événement d'origine. Cela fournit une piste claire et de haut niveau de toutes les activités liées à une seule action utilisateur.
  • Insights Détaillés d'Exécution : Pour chaque exécution de fonction (succès et échecs), Inngest fournit des logs détaillés via ses rapports ack (acknowledge) et nack (negative acknowledgment). Ces logs incluent les traces de pile d'erreurs, les charges utiles complètes des requêtes et les charges utiles de réponse sérialisées pour chaque étape d'exécution individuelle.
  • Métriques Opérationnelles : Au-delà des logs, nous avons obtenu des métriques critiques sur la santé des fonctions, y compris les taux de réussite, les taux d'échec et le nombre de nouvelles tentatives, nous permettant de surveiller continuellement la fiabilité et la latence de nos flux de travail distribués.

Construction pour la Résilience

La mise en garde concernant le fait de s'appuyer sur un traitement d'événements pur est que, bien qu'Inngest mette efficacement en file d'attente les exécutions de fonctions, les événements eux-mêmes ne sont pas mis en file d'attente en interne au sens traditionnel d'un broker de messagerie. Cette absence d'une file d'attente d'événements explicite peut être problématique dans des scénarios à fort trafic en raison de conditions de course potentielles ou d'événements perdus si le point de terminaison d'ingestion est surchargé.

Pour résoudre ce problème et imposer une durabilité stricte des événements, nous avons implémenté un système de file d'attente dédié comme tampon.

AWS Simple Queue System (SQS) était le système de choix (bien que tout système de file d'attente robuste soit faisable), étant donné notre infrastructure existante sur AWS. Nous avons conçu un système à deux files d'attente : une File d'attente principale et une File d'attente de lettres mortes (DLQ).

Nous avons établi un environnement de travail Elastic Beanstalk (EB) spécifiquement configuré pour consommer des messages directement depuis la File d'attente principale. Si un message dans la File d'attente principale ne peut pas être traité par le travailleur EB un certain nombre de fois, la File d'attente principale déplace automatiquement le message échoué vers la DLQ dédiée. Cela garantit qu'aucun événement n'est perdu définitivement s'il ne parvient pas à se déclencher ou à être récupéré par Inngest. Cet environnement de travail diffère d'un environnement de serveur web EB standard, car sa seule responsabilité est la consommation et le traitement des messages (dans ce cas, le transfert du message consommé vers le point de terminaison de l'API Inngest).

COMPRENDRE LES LIMITES ET LES SPÉCIFICATIONS

Une partie sous-estimée et plutôt pertinente de la construction d'une infrastructure à l'échelle de l'entreprise est qu'elle consomme des ressources, et elles sont de longue durée. L'architecture des microservices fournit une scalabilité par service. Le stockage, la RAM et les délais d'attente des ressources entreront en jeu. Notre spécification pour le type d'instance AWS, par exemple, est passée rapidement de t3.micro à t3.small, et est maintenant fixée à t3.medium. Pour les tâches d'arrière-plan de longue durée et intensives en CPU, la mise à l'échelle horizontale avec de petites instances échoue car le goulot d'étranglement est le temps nécessaire pour traiter une seule tâche, et non le volume de nouvelles tâches entrant dans la file d'attente.

Les tâches ou fonctions comme le transcodage, l'intégration sont généralement limitées par le CPU et limitées par la mémoire. Limitées par le CPU car elles nécessitent une utilisation CPU soutenue et intense, et limitées par la mémoire car elles nécessitent souvent une RAM substantielle pour charger de grands modèles ou gérer efficacement de grands fichiers ou charges utiles.

En fin de compte, cette architecture augmentée, plaçant la durabilité de SQS et l'exécution contrôlée d'un environnement de travail EB directement en amont de l'API Inngest, a fourni une résilience essentielle. Nous avons obtenu une propriété stricte des événements, éliminé les conditions de course pendant les pics de trafic et gagné un mécanisme de lettre morte non volatile. Nous avons exploité Inngest pour ses capacités d'orchestration de flux de travail et de débogage, tout en nous appuyant sur les primitives AWS pour un débit de messages et une durabilité maximaux. Le système résultant est non seulement évolutif mais hautement auditable, traduisant avec succès des tâches backend complexes et de longue durée en micro-étapes sécurisées, observables et tolérantes aux pannes.


Building Spotify for Sermons. a été initialement publié dans Coinmonks sur Medium, où les gens continuent la conversation en mettant en évidence et en répondant à cette histoire.

Clause de non-responsabilité : les articles republiés sur ce site proviennent de plateformes publiques et sont fournis à titre informatif uniquement. Ils ne reflètent pas nécessairement les opinions de MEXC. Tous les droits restent la propriété des auteurs d'origine. Si vous estimez qu'un contenu porte atteinte aux droits d'un tiers, veuillez contacter service@support.mexc.com pour demander sa suppression. MEXC ne garantit ni l'exactitude, ni l'exhaustivité, ni l'actualité des contenus, et décline toute responsabilité quant aux actions entreprises sur la base des informations fournies. Ces contenus ne constituent pas des conseils financiers, juridiques ou professionnels, et ne doivent pas être interprétés comme une recommandation ou une approbation de la part de MEXC.