SDK di esecuzione durevole - AWS Lambda

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

SDK di esecuzione durevole

L'SDK di esecuzione durevole è la base per la creazione di funzioni durevoli. Fornisce le primitive necessarie per controllare i progressi, gestire i nuovi tentativi e gestire il flusso di esecuzione. L'SDK elimina la complessità della gestione e della riproduzione dei checkpoint, consentendoti di scrivere codice sequenziale che diventa automaticamente tollerante ai guasti.

L'SDK è disponibile per JavaScript TypeScript, e Python. Per la documentazione completa e gli esempi relativi alle API, consulta JavaScript/TypeScript SDK e Python SDK on. GitHub

DurableContext

L'SDK fornisce alla funzione un DurableContext oggetto che espone tutte le operazioni durevoli. Questo contesto sostituisce il contesto Lambda standard e fornisce metodi per creare checkpoint, gestire il flusso di esecuzione e coordinarsi con sistemi esterni.

Per utilizzare l'SDK, avvolgi il tuo gestore Lambda con il wrapper di esecuzione durevole:

TypeScript
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js'; export const handler = withDurableExecution( async (event: any, context: DurableContext) => { // Your function receives DurableContext instead of Lambda context // Use context.step(), context.wait(), etc. return result; } );
Python
from aws_durable_execution_sdk_python import durable_execution, DurableContext @durable_execution def handler(event: dict, context: DurableContext): # Your function receives DurableContext # Use context.step(), context.wait(), etc. return result

Il wrapper intercetta l'invocazione della funzione, carica qualsiasi registro di checkpoint esistente e fornisce il file che gestisce la riproduzione e il checkpoint. DurableContext

Cosa fa l'SDK

L'SDK gestisce tre responsabilità fondamentali che consentono un'esecuzione duratura:

Gestione dei checkpoint: l'SDK crea automaticamente i checkpoint man mano che la funzione esegue operazioni durevoli. Ogni checkpoint registra il tipo di operazione, gli input e i risultati. Quando la funzione completa un passaggio, l'SDK mantiene il checkpoint prima di continuare. Ciò garantisce che la funzione possa riprendere dopo qualsiasi operazione completata in caso di interruzione.

Coordinamento della riproduzione: quando la funzione riprende dopo una pausa o un'interruzione, l'SDK esegue la riproduzione. Esegue il codice dall'inizio ma salta le operazioni completate, utilizzando i risultati dei checkpoint memorizzati invece di rieseguirli. L'SDK garantisce che la riproduzione sia deterministica: con gli stessi input e lo stesso registro dei checkpoint, la funzione produce gli stessi risultati.

Isolamento dello stato: l'SDK mantiene lo stato di esecuzione separatamente dalla logica aziendale. Ogni esecuzione durevole ha il proprio registro dei checkpoint a cui le altre esecuzioni non possono accedere. L'SDK crittografa i dati dei checkpoint inattivi e garantisce che lo stato rimanga coerente tra i replay.

Come funziona il checkpoint

Quando si chiama un'operazione duratura, l'SDK segue questa sequenza:

  1. Verifica la presenza di un checkpoint esistente: l'SDK verifica se questa operazione è già stata completata in una precedente chiamata. Se esiste un checkpoint, l'SDK restituisce il risultato memorizzato senza rieseguire l'operazione.

  2. Esegui l'operazione: se non esiste alcun checkpoint, l'SDK esegue il codice operativo. Per quanto riguarda i passaggi, ciò significa chiamare la funzione. Per le attese, ciò significa la ripresa della pianificazione.

  3. Crea checkpoint: una volta completata l'operazione, l'SDK serializza il risultato e crea un checkpoint. Il checkpoint include il tipo di operazione, il nome, gli input, il risultato e il timestamp.

  4. Checkpoint persistente: l'SDK chiama l'API checkpoint Lambda per rendere persistente il checkpoint. Ciò garantisce che il checkpoint sia duraturo prima di continuare l'esecuzione.

  5. Risultato di ritorno: l'SDK restituisce il risultato dell'operazione al codice, che continua con l'operazione successiva.

Questa sequenza assicura che, una volta completata un'operazione, il risultato venga archiviato in modo sicuro. Se la funzione viene interrotta in qualsiasi momento, l'SDK può riprodurla fino all'ultimo checkpoint completato.

Comportamento di riproduzione

Quando la funzione riprende dopo una pausa o un'interruzione, l'SDK esegue la riproduzione:

  1. Carica il registro del checkpoint: l'SDK recupera il registro dei checkpoint per questa esecuzione da Lambda.

  2. Esegui dall'inizio: l'SDK richiama la funzione di gestione dall'inizio, non dal punto in cui è stata messa in pausa.

  3. Ignora le operazioni durevoli completate: man mano che il codice richiama operazioni durevoli, l'SDK confronta ciascuna di esse con il registro del checkpoint. Per operazioni durevoli completate, l'SDK restituisce il risultato memorizzato senza eseguire il codice operativo.

    Nota

    Se il risultato di un contesto secondario era maggiore della dimensione massima del checkpoint (256 KB), il codice del contesto viene eseguito nuovamente durante la riproduzione. Ciò consente di ottenere risultati di grandi dimensioni a partire dalle operazioni durevoli eseguite all'interno del contesto, che verranno ricercate dal registro del checkpoint. Pertanto è imperativo eseguire codice deterministico solo nel contesto stesso. Quando si utilizzano contesti secondari con risultati di grandi dimensioni, è consigliabile eseguire un lavoro di lunga durata o non deterministico all'interno di passaggi ed eseguire solo attività di breve durata che combinano i risultati nel contesto stesso.

  4. Riprendi al punto di interruzione: quando l'SDK raggiunge un'operazione senza checkpoint, viene eseguita normalmente e crea nuovi checkpoint man mano che le operazioni durevoli vengono completate.

Questo meccanismo di replay richiede che il codice sia deterministico. Con gli stessi input e lo stesso registro dei checkpoint, la funzione deve effettuare la stessa sequenza di chiamate operative durevoli. L'SDK lo impone convalidando che i nomi e i tipi di operazioni corrispondano al registro del checkpoint durante la riproduzione.

Operazioni durevoli disponibili

DurableContextFornisce operazioni per diversi modelli di coordinamento. Ogni operazione durevole crea automaticamente dei checkpoint, assicurando che la funzione possa riprendere da qualsiasi momento.

Fasi

Esegue la logica aziendale con checkpoint e nuovi tentativi automatici. Utilizza i passaggi per le operazioni che richiamano servizi esterni, eseguono calcoli o eseguono qualsiasi logica che dovrebbe essere sottoposta a checkpoint. L'SDK crea un checkpoint prima e dopo il passaggio, memorizzando il risultato per la riproduzione.

TypeScript
const result = await context.step('process-payment', async () => { return await paymentService.charge(amount); });
Python
result = context.step( lambda _: payment_service.charge(amount), name='process-payment' )

I passaggi supportano strategie di ripetizione configurabili, semantica di esecuzione (at-most-once or) e serializzazione personalizzata. at-least-once

Stati di attesa

Sospende l'esecuzione per una durata specificata senza consumare risorse di elaborazione. L'SDK crea un checkpoint, termina l'invocazione della funzione e pianifica la ripresa. Al termine dell'attesa, Lambda richiama nuovamente la funzione e l'SDK viene riprodotto fino al punto di attesa prima di continuare.

TypeScript
// Wait 1 hour without charges await context.wait({ seconds: 3600 });
Python
# Wait 1 hour without charges context.wait(3600)

Callback

I callback consentono alla funzione di mettere in pausa e attendere che sistemi esterni forniscano input. Quando si crea un callback, l'SDK genera un ID di callback univoco e crea un checkpoint. La funzione viene quindi sospesa (termina la chiamata) senza incorrere in costi di calcolo. I sistemi esterni inviano i risultati del callback utilizzando SendDurableExecutionCallbackSuccess o SendDurableExecutionCallbackFailure Lambda APIs. Quando viene inviata una callback, Lambda richiama nuovamente la funzione, l'SDK viene riprodotto fino al punto di callback e la funzione continua con il risultato del callback.

L'SDK fornisce due metodi per lavorare con i callback:

CreateCallback: crea un callback e restituisce sia una promessa che un ID di callback. L'ID di callback viene inviato a un sistema esterno, che invia il risultato utilizzando l'API Lambda.

TypeScript
const [promise, callbackId] = await context.createCallback('approval', { timeout: { hours: 24 } }); await sendApprovalRequest(callbackId, requestData); const approval = await promise;
Python
callback = context.create_callback( name='approval', config=CallbackConfig(timeout_seconds=86400) ) context.step( lambda _: send_approval_request(callback.callback_id), name='send_request' ) approval = callback.result()

waitForCallback: semplifica la gestione delle callback combinando la creazione e l'invio delle callback in un'unica operazione. L'SDK crea il callback, esegue la funzione di invio con l'ID di callback e attende il risultato.

TypeScript
const result = await context.waitForCallback( 'external-api', async (callbackId, ctx) => { await submitToExternalAPI(callbackId, requestData); }, { timeout: { minutes: 30 } } );
Python
result = context.wait_for_callback( lambda callback_id: submit_to_external_api(callback_id, request_data), name='external-api', config=WaitForCallbackConfig(timeout_seconds=1800) )

Configura i timeout per evitare che le funzioni restino in attesa all'infinito. Se scade un callback, l'SDK genera un timeout CallbackError e la tua funzione può gestire il caso di timeout. Utilizza i timeout del battito cardiaco per le richiamate di lunga durata per rilevare quando i sistemi esterni smettono di rispondere.

Utilizza i callback per human-in-the-loop flussi di lavoro, integrazione di sistemi esterni, risposte webhook o qualsiasi scenario in cui l'esecuzione debba essere messa in pausa per l'input esterno.

Esecuzione parallela

Esegue più operazioni contemporaneamente con il controllo della concorrenza opzionale. L'SDK gestisce l'esecuzione parallela, crea checkpoint per ogni operazione e gestisce gli errori in base alla politica di completamento.

TypeScript
const results = await context.parallel([ async (ctx) => ctx.step('task1', async () => processTask1()), async (ctx) => ctx.step('task2', async () => processTask2()), async (ctx) => ctx.step('task3', async () => processTask3()) ]);
Python
results = context.parallel( lambda ctx: ctx.step(lambda _: process_task1(), name='task1'), lambda ctx: ctx.step(lambda _: process_task2(), name='task2'), lambda ctx: ctx.step(lambda _: process_task3(), name='task3') )

Utilizzato parallel per eseguire operazioni indipendenti contemporaneamente.

Eseguire la mappatura

Esegue contemporaneamente un'operazione su ogni elemento di una matrice con controllo di concorrenza opzionale. L'SDK gestisce l'esecuzione simultanea, crea checkpoint per ogni operazione e gestisce gli errori in base alla politica di completamento.

TypeScript
const results = await context.map(itemArray, async (ctx, item, index) => ctx.step('task', async () => processItem(item, index)) );
Python
results = context.map( item_array, lambda ctx, item, index: ctx.step( lambda _: process_item(item, index), name='task' ) )

Utilizzato map per elaborare gli array con controllo della concorrenza.

Contesti infantili

Crea un contesto di esecuzione isolato per le operazioni di raggruppamento. I contesti secondari dispongono di un proprio registro dei checkpoint e possono contenere più passaggi, attese e altre operazioni. L'SDK tratta l'intero contesto secondario come una singola unità per riprovare e ripristinare.

Utilizza i contesti secondari per organizzare flussi di lavoro complessi, implementare flussi di lavoro secondari o isolare operazioni da riprovare contemporaneamente.

TypeScript
const result = await context.runInChildContext( 'batch-processing', async (childCtx) => { return await processBatch(childCtx, items); } );
Python
result = context.run_in_child_context( lambda child_ctx: process_batch(child_ctx, items), name='batch-processing' )

Il meccanismo di replay richiede che le operazioni durevoli avvengano in un ordine deterministico. Utilizzando più contesti secondari è possibile eseguire contemporaneamente più flussi di lavoro e il determinismo si applica separatamente all'interno di ciascun contesto. Ciò consente di creare funzioni ad alte prestazioni che utilizzano in modo efficiente più core della CPU.

Ad esempio, immaginiamo di iniziare due contesti secondari, A e B. Nella chiamata iniziale, i passaggi all'interno dei contesti sono stati eseguiti in questo ordine, con i passaggi «A» eseguiti contemporaneamente ai passaggi «B»: A1, B1, B2, A2, A3. Dopo la riproduzione, i tempi sono molto più rapidi in quanto i risultati vengono recuperati dal registro dei checkpoint e i passaggi vengono eseguiti in un ordine diverso: B1, A1, A2, B2, A3. Poiché i passaggi «A» sono stati rilevati nell'ordine corretto (A1, A2, A3) e i passaggi «B» sono stati rilevati nell'ordine corretto (B1, B2), l'esigenza del determinismo è stata soddisfatta correttamente.

Attese condizionali

Sondaggi relativi a una condizione con checkpoint automatico tra un tentativo e l'altro. L'SDK esegue la funzione di controllo, crea un checkpoint con il risultato, attende in base alla strategia scelta e ripete l'operazione finché la condizione non viene soddisfatta.

TypeScript
const result = await context.waitForCondition( async (state, ctx) => { const status = await checkJobStatus(state.jobId); return { ...state, status }; }, { initialState: { jobId: 'job-123', status: 'pending' }, waitStrategy: (state) => state.status === 'completed' ? { shouldContinue: false } : { shouldContinue: true, delay: { seconds: 30 } } } );
Python
result = context.wait_for_condition( lambda state, ctx: check_job_status(state['jobId']), config=WaitForConditionConfig( initial_state={'jobId': 'job-123', 'status': 'pending'}, wait_strategy=lambda state, attempt: {'should_continue': False} if state['status'] == 'completed' else {'should_continue': True, 'delay': 30} ) )

Utilizzalo waitForCondition per eseguire il polling di sistemi esterni, attendere che le risorse siano pronte o implementare nuovi tentativi con backoff.

Invocazione della funzione

Richiama un'altra funzione Lambda e ne attende il risultato. L'SDK crea un checkpoint, richiama la funzione di destinazione e riprende la funzione al termine della chiamata. Ciò consente la composizione delle funzioni e la scomposizione del flusso di lavoro.

TypeScript
const result = await context.invoke( 'invoke-processor', 'arn:aws:lambda:us-east-1:123456789012:function:processor', { data: inputData } );
Python
result = context.invoke( 'arn:aws:lambda:us-east-1:123456789012:function:processor', {'data': input_data}, name='invoke-processor' )

Come viene misurata la durata delle operazioni

Ogni operazione duratura eseguita DurableContext crea punti di controllo per tenere traccia dell'avanzamento dell'esecuzione e archiviare i dati sullo stato. Queste operazioni comportano addebiti in base al loro utilizzo e i checkpoint possono contenere dati che contribuiscono ai costi di scrittura e conservazione dei dati. I dati archiviati includono i dati degli eventi di invocazione, i payload restituiti dai passaggi e i dati trasmessi durante il completamento dei callback. Comprendere come viene misurata la durata delle operazioni consente di stimare i costi di esecuzione e ottimizzare i flussi di lavoro. Per i dettagli sui prezzi, consulta la pagina dei prezzi di Lambda.

La dimensione del payload si riferisce alla dimensione dei dati serializzati necessari a garantire la persistenza di un'operazione durevole. I dati vengono misurati in byte e la dimensione può variare a seconda del serializzatore utilizzato dall'operazione. Il payload di un'operazione potrebbe essere il risultato stesso del completamento con successo o l'oggetto di errore serializzato se l'operazione non è riuscita.

Operazioni di base

Le operazioni di base sono gli elementi costitutivi fondamentali per funzioni durevoli:

Operation Tempistica dei checkpoint Numero di operazioni Dati persistenti
Esecuzione Avviato 1 Dimensione del payload di input
Esecuzione Completato () Succeeded/Failed/Stopped 0 Dimensione del payload in uscita
Fase Retry/Succeeded/Failed 1 + Nessun tentativo Dimensione del payload restituita da ogni tentativo
Attendi Avviato 1 N/D
WaitForCondition Ogni tentativo di sondaggio 1 + N sondaggi Dimensione del payload restituita da ogni tentativo di sondaggio
Riprova a livello di chiamata Avviato 1 Payload per l'oggetto di errore

Operazioni di callback

Le operazioni di callback consentono alla funzione di mettere in pausa e attendere che sistemi esterni forniscano input. Queste operazioni creano punti di controllo quando il callback viene creato e quando è completato:

Operation Tempistica del checkpoint Numero di operazioni Dati persistenti
CreateCallback Avviato 1 N/D
Completamento del callback tramite chiamata API Completato 0 Payload di callback
WaitForCallback Avviato 3+ N tentativi (contesto + callback + step) Payload restituiti dai tentativi di invio, più due copie del payload di callback

Operazioni composte

Le operazioni composte combinano più operazioni durevoli per gestire modelli di coordinamento complessi come esecuzione parallela, elaborazione di array e contesti annidati:

Operation tempistica dei checkpoint Numero di operazioni Dati persistenti
Parallela Avviato 1+ N rami (1 contesto principale + N contesti secondari) Fino a due copie della dimensione del payload restituita da ciascun ramo, più gli stati di ogni ramo
Mappa Avviato 1+ N rami (1 contesto genitore+N contesti secondari) Fino a due copie della dimensione del payload restituita da ogni iterazione, più gli stati di ogni iterazione
Aiutanti di Promise Completato 1 Dimensione del payload restituita dalla promessa
RunInChildContext Riuscito/non riuscito 1 Dimensione del payload restituita dal contesto secondario

Per i contesti, ad esempio provenienti da runInChildContext o utilizzati internamente da operazioni composte, i risultati inferiori a 256 KB vengono controllati direttamente. I risultati più grandi non vengono archiviati, ma vengono ricostruiti durante la riproduzione rielaborando le operazioni del contesto.