Costruire per Sistemi di Grandi Dimensioni e Job in Background a Lunga Durata.Credito: Ilias Chebbi su Unsplash Mesi fa, ho assunto il ruolo che richiedeva la costruzione dell'infrastCostruire per Sistemi di Grandi Dimensioni e Job in Background a Lunga Durata.Credito: Ilias Chebbi su Unsplash Mesi fa, ho assunto il ruolo che richiedeva la costruzione dell'infrast

Costruire Spotify per i Sermoni.

2025/12/11 21:15

Costruire per Sistemi di Grandi Dimensioni e Lavori in Background di Lunga Durata.

Credito: Ilias Chebbi su Unsplash

Mesi fa, ho assunto il ruolo che richiedeva la costruzione di infrastrutture per lo streaming di media (audio). Ma oltre a servire l'audio come blocchi trasmissibili, c'erano lavori di elaborazione dei media di lunga durata e un'ampia pipeline RAG che si occupava di trascrizione, transcodifica, embedding e aggiornamenti sequenziali dei media. Costruire un MVP con una mentalità orientata alla produzione ci ha fatto reiterare fino a raggiungere un sistema senza interruzioni. Il nostro approccio è stato quello in cui abbiamo integrato funzionalità e lo stack sottostante di priorità.

Di Primaria Preoccupazione:

Nel corso della costruzione, ogni iterazione è arrivata come risposta a un'esigenza immediata e spesso "onnicomprensiva". La preoccupazione iniziale era la messa in coda dei lavori, che si è rivelata sufficiente con Redis; semplicemente lanciavamo e dimenticavamo. Bull MQ nel framework NEST JS ci ha dato un controllo ancora migliore sui tentativi, i backlog e la coda delle lettere morte. Localmente e con alcuni payload in produzione, abbiamo ottenuto il flusso dei media corretto. Presto siamo stati gravati dal peso dell'Osservabilità:
Log → Registro dei lavori (richieste, risposte, errori).
Metriche → Quanto / quanto spesso questi lavori vengono eseguiti, falliscono, completano, ecc.
Tracce → Il percorso che un lavoro ha seguito attraverso i servizi (funzioni/metodi chiamati all'interno del percorso di flusso).

Puoi risolvere alcuni di questi progettando API e costruendo una dashboard personalizzata in cui inserirli, ma il problema della scalabilità sarà sufficiente. E infatti, abbiamo progettato le API.

Costruire per l'Osservabilità

La sfida di gestire flussi di lavoro backend complessi e di lunga durata, dove i fallimenti devono essere recuperabili e lo stato deve essere durevole, Inngest è diventata la nostra salvezza architettonica. Ha fondamentalmente riformulato il nostro approccio: ogni lavoro in background di lunga durata diventa una funzione in background, attivata da un evento specifico.

Ad esempio, un evento Transcription.request attiverà una funzione TranscribeAudio. Questa funzione potrebbe contenere step-run per: fetch_audio_metadata, deepgram_transcribe, parse_save_trasncription e notify_user.

Decostruire il Flusso di Lavoro: La Funzione Inngest e gli Step-run

Il primitivo di durabilità principale sono gli step-run. Una funzione in background è internamente suddivisa in questi step-run, ciascuno contenente un blocco minimo e atomico di logica.

  • Logica Atomica: Una funzione esegue la tua logica di business passo dopo passo. Se un passaggio fallisce, lo stato dell'intera esecuzione viene preservato e l'esecuzione può essere ritentata. Questo riavvia la funzione dall'inizio. I singoli passaggi o step-run non possono essere ritentati isolatamente.
  • Serializzazione della Risposta: Uno step-run è definito dalla sua risposta. Questa risposta viene automaticamente serializzata, il che è essenziale per preservare strutture di dati complesse o fortemente tipizzate attraverso i confini di esecuzione. Gli step-run successivi possono analizzare in modo affidabile questa risposta serializzata, o la logica può essere unita in un unico passaggio per efficienza.
  • Disaccoppiamento e Pianificazione: All'interno di una funzione, possiamo mettere in coda o pianificare condizionalmente nuovi eventi dipendenti, abilitando modelli complessi di fan-out/fan-in e pianificazione a lungo termine fino a un anno. Errori e successi in qualsiasi punto possono essere catturati, ramificati e gestiti più avanti nel flusso di lavoro.

Astratto della funzione 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 };
},
);
};

Il modello event-driven di Inngest fornisce un'intuizione granulare in ogni esecuzione del flusso di lavoro:

  • Tracciamento Completo degli Eventi: Ogni esecuzione di funzione in coda viene registrata rispetto al suo evento di origine. Questo fornisce una traccia chiara e di alto livello di tutte le attività relative a una singola azione utente.
  • Approfondimenti Dettagliati sull'Esecuzione: Per ogni esecuzione di funzione (sia successi che fallimenti), Inngest fornisce log dettagliati tramite il suo reporting ack (acknowledge) e nack (negative acknowledgment). Questi log includono tracce di stack di errori, payload di richiesta completi e payload di risposta serializzati per ogni singolo step-run.
  • Metriche Operative: Oltre ai log, abbiamo ottenuto metriche critiche sulla salute delle funzioni, inclusi tassi di successo, tassi di fallimento e conteggio dei tentativi, permettendoci di monitorare continuamente l'affidabilità e la latenza dei nostri flussi di lavoro distribuiti.

Costruire per la Resilienza

L'avvertenza nell'affidarsi all'elaborazione di eventi puri è che mentre Inngest mette in coda efficientemente le esecuzioni di funzioni, gli eventi stessi non sono messi in coda internamente nel senso tradizionale di un broker di messaggistica. Questa assenza di una coda di eventi esplicita può essere problematica in scenari ad alto traffico a causa di potenziali condizioni di gara o eventi persi se l'endpoint di ingestione è sovraccarico.

Per affrontare questo problema e imporre una rigorosa durabilità degli eventi, abbiamo implementato un sistema di accodamento dedicato come buffer.

AWS Simple Queue System (SQS) è stato il sistema scelto (anche se qualsiasi sistema di accodamento robusto è fattibile), data la nostra infrastruttura esistente su AWS. Abbiamo architettato un sistema a due code: una Coda Principale e una Coda delle Lettere Morte (DLQ).

Abbiamo stabilito un Ambiente Worker Elastic Beanstalk (EB) specificamente configurato per consumare messaggi direttamente dalla Coda Principale. Se un messaggio nella Coda Principale non viene elaborato dal Worker EB un numero prestabilito di volte, la Coda Principale sposta automaticamente il messaggio fallito nella DLQ dedicata. Questo assicura che nessun evento venga perso permanentemente se non riesce ad attivare o ad essere prelevato da Inngest. Questo ambiente worker differisce da un ambiente server web EB standard, poiché la sua unica responsabilità è il consumo e l'elaborazione dei messaggi (in questo caso, l'inoltro del messaggio consumato all'endpoint API di Inngest).

COMPRENDERE LIMITI E SPECIFICHE

Una parte sottovalutata e piuttosto pertinente della costruzione di infrastrutture su scala aziendale è che consuma risorse, e sono di lunga durata. L'architettura dei microservizi fornisce scalabilità per servizio. Archiviazione, RAM e timeout delle risorse entreranno in gioco. La nostra specifica per il tipo di istanza AWS, ad esempio, è passata rapidamente da t3.micro a t3.small, e ora è fissata a t3.medium. Per lavori in background di lunga durata e ad alta intensità di CPU, la scalabilità orizzontale con istanze minuscole fallisce perché il collo di bottiglia è il tempo necessario per elaborare un singolo lavoro, non il volume di nuovi lavori che entrano nella coda.

Lavori o funzioni come transcodifica, embedding sono tipicamente vincolati dalla CPU e vincolati dalla memoria. Vincolati dalla CPU perché richiedono un uso sostenuto e intenso della CPU, e vincolati dalla memoria perché spesso richiedono RAM sostanziale per caricare modelli di grandi dimensioni o gestire file o payload di grandi dimensioni in modo efficiente.

In definitiva, questa architettura aumentata, che posiziona la durabilità di SQS e l'esecuzione controllata di un ambiente Worker EB direttamente a monte dell'API Inngest, ha fornito una resilienza essenziale. Abbiamo ottenuto una rigorosa proprietà degli eventi, eliminato le condizioni di gara durante i picchi di traffico e acquisito un meccanismo di lettere morte non volatile. Abbiamo sfruttato Inngest per le sue capacità di orchestrazione del flusso di lavoro e di debug, mentre ci siamo affidati ai primitivi AWS per il massimo throughput dei messaggi e durabilità. Il sistema risultante non è solo scalabile ma altamente verificabile, traducendo con successo lavori backend complessi e di lunga durata in micro-passi sicuri, osservabili e tolleranti ai guasti.


Building Spotify for Sermons. è stato originariamente pubblicato in Coinmonks su Medium, dove le persone stanno continuando la conversazione evidenziando e rispondendo a questa storia.

Disclaimer: gli articoli ripubblicati su questo sito provengono da piattaforme pubbliche e sono forniti esclusivamente a scopo informativo. Non riflettono necessariamente le opinioni di MEXC. Tutti i diritti rimangono agli autori originali. Se ritieni che un contenuto violi i diritti di terze parti, contatta service@support.mexc.com per la rimozione. MEXC non fornisce alcuna garanzia in merito all'accuratezza, completezza o tempestività del contenuto e non è responsabile per eventuali azioni intraprese sulla base delle informazioni fornite. Il contenuto non costituisce consulenza finanziaria, legale o professionale di altro tipo, né deve essere considerato una raccomandazione o un'approvazione da parte di MEXC.