Gestire gli errori in applicazioni serverless
con AWS Step Functions e AWS Lambda
In questo tutorial, imparerai a utilizzare AWS Step Functions per gestire gli errori di runtime dei flussi di lavoro. AWS Step Functions è un servizio di orchestrazione serverless che consente di coordinare facilmente più funzioni Lambda in flussi di lavoro flessibili, di cui è semplice eseguire il debug, e facili da modificare. AWS Lambda è un servizio di elaborazione che consente di eseguire codice senza dover effettuare il provisioning né gestire server.
Le funzioni Lambda possono talvolta non andare a buon fine, come quando viene sollevata un’eccezione non gestita, quando le funzioni sono in esecuzione per un tempo maggiore del timeout configurato o quando esauriscono la memoria. Scrivere e mantenere la logica di gestione degli errori in tutte le funzioni Lambda per gestire situazioni come il throttling API o i timeout dei socket può richiedere tempo ed è spesso complicato, specie per le applicazioni distribuite. Incorporare questo codice in ogni funzione Lambda crea dipendenze tra esse e può essere difficile mantenere tutte queste connessioni mentre le cose cambiano.
Per evitare il problema e per ridurre la quantità di codice per la gestione di errori che devi scrivere, puoi utilizzare AWS Step Functions per creare un flusso di lavoro serverless che supporti la gestione degli errori delle funzioni. Indipendentemente dal fatto che l'errore sia l'eccezione di una funzione creata dallo sviluppatore (ad es. file non trovato) o imprevisto (ad es. memoria non sufficiente), puoi configurare Step Functions affinché risponda con una logica condizionale in base al tipo di errore che si è verificato. Separando in questo modo la logica del flusso di lavoro dalla logica di business, puoi modificare il modo in cui il tuo flusso di lavoro risponde agli errori senza modificare la logica di business delle tue funzioni Lambda.
In questo tutorial, progetterai ed eseguirai un flusso di lavoro serverless utilizzando AWS Step Functions che gestiranno elegantemente questi errori. Imparerai a creare una funzione AWS Lambda che simula le chiamate a un’API RESTful e restituisce vari codici di risposta ed eccezioni. Quindi, utilizzerai AWS Step Functions per creare una macchina a stati con funzionalità Retry e Catch che risponda con logica diversa in base all’eccezione sollevata.
Questo tutorial richiede un account AWS
Non sono previsti costi aggiuntivi per l'utilizzo di AWS Step Functions o AWS Lambda. Le risorse create in questo tutorial sono idonee per il piano gratuito.
Fase 1. Creazione di una funzione Lambda per simulare un’API
In questa fase, creerai una funzione Lambda che simulerà alcune interazioni API di base. La funzione Lambda solleva eccezioni per simulare le risposte di un’API fittizia, in base al codice di errore che fornisci come input nel parametro dell’evento.
a. Apri la Console di gestione AWS e tieni sotto mano questa guida dettagliata. Quando viene caricata la schermata, inserisci nome utente e password per iniziare. Quindi, digita Lambda nella barra di ricerca e seleziona Lambda per aprire la console di servizio.
c. Lascia selezionato Author from scratch (Crea da zero). Quindi, configura la funzione Lambda come segue:
Per Name (Nome), digita MockAPIFunction.
Per Runtime, scegli Python 3.6.
Per Role (Ruolo), seleziona Create custom role (Crea ruolo personalizzato).
Si apre una nuova finestra IAM. In Role name (Nome ruolo), mantieni lambda_basic_execution e fai clic su Allow (Consenti). Vieni riportato automaticamente alla console Lambda.
Fai clic su Create function (Crea funzione).
d. Nella schermata MockAPIFunction , scorri verso il basso fino alla sezione Function code (Codice funzione). In questo tutorial, imparerai a creare una funzione che utilizza il modello di programmazione per la creazione delle funzioni Lambda in Python. Nella finestra del codice, sostituisci tutto il codice con il codice seguente, quindi scegli Save (Salva).
class TooManyRequestsException(Exception): pass
class ServerUnavailableException(Exception): pass
class UnknownException(Exception): pass
def lambda_handler(event, context):
statuscode = event["statuscode"]
if statuscode == "429":
raise TooManyRequestsException('429 Too Many Requests')
elif statuscode == "503":
raise ServerUnavailableException('503 Server Unavailable')
elif statuscode == "200":
return '200 OK'
else:
raise UnknownException('Unknown error')
e. Una volta creata la funzione Lambda, scorri fino all’inizio della finestra e nota il relativo Amazon Resource Name (ARN) nell’angolo in alto a destra della pagina. Amazon Resource Names (ARNs) identifica in modo univoco le risorse AWS e ti consente di monitorare e utilizzare le voci e le policy AWS nei servizi AWS e nelle chiamate API. Quando devi fare riferimento a una risorsa specifica da Step Functions, serve un ARN.
Fase 2. Creazione di un ruolo AWS Identity and Access Management (IAM)
AWS Step Functions può eseguire codice e accedere ad altre risorse AWS (ad es. dati archiviati nei bucket Amazon S3). Per conservare la sicurezza, devi concedere l’accesso Step Functions a queste risorse utilizzando AWS Identity and Access Management (IAM).
Fase 3. Crea una macchina a stati AWS Step Functions
Ora che hai creato la funzione Lambda semplice che simula la risposta API, puoi creare una macchina a stati Step Functions per chiamare la API e gestire le eccezioni.
In questa fase, utilizzerai la console Step Functions per creare una macchina a stati che utilizza uno stato Attività con un campo Retry e Catch per gestire i diversi codici di risposta API. Utilizzerai uno stato Attività per invocare la funzione Lambda API simulata, che restituirà il codice di stato API che hai fornito come input nella macchina a stati.
a. Apri la console AWS Step Functions. Nella pagina Creazione di una macchina a stati, seleziona Author from scratch (Crea da zero). Nella sezione Details (Dettagli), assegna alla tua macchina a stati il nome MyAPIStateMachine, quindi seleziona I will use an existing role (Utilizzerò un ruolo esistente).
b. Quindi, progetterai una macchina a stati che svolgerà diverse operazioni a seconda della risposta della tua API simulata. Se non è possibile raggiungere l’API, il flusso di lavoro riprova. I nuovi tentativi sono un metodo utile per affrontare errori temporanei. Il flusso di lavoro acquisisce anche eccezioni diverse sollevate dall’API simulata.
Sostituisci il contenuto della sezione State machine definition (Definizione macchina a stati) con il seguente codice:
{
"Comment": "An example of using retry and catch to handle API responses",
"StartAt": "Call API",
"States": {
"Call API": {
"Type": "Task",
"Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
"Next" : "OK",
"Comment": "Catch a 429 (Too many requests) API exception, and resubmit the failed request in a rate-limiting fashion.",
"Retry" : [ {
"ErrorEquals": [ "TooManyRequestsException" ],
"IntervalSeconds": 1,
"MaxAttempts": 2
} ],
"Catch": [
{
"ErrorEquals": ["TooManyRequestsException"],
"Next": "Wait and Try Later"
}, {
"ErrorEquals": ["ServerUnavailableException"],
"Next": "Server Unavailable"
}, {
"ErrorEquals": ["States.ALL"],
"Next": "Catch All"
}
]
},
"Wait and Try Later": {
"Type": "Wait",
"Seconds" : 1,
"Next" : "Change to 200"
},
"Server Unavailable": {
"Type": "Fail",
"Error":"ServerUnavailable",
"Cause": "The server is currently unable to handle the request."
},
"Catch All": {
"Type": "Fail",
"Cause": "Unknown error!",
"Error": "An error of unknown type occurred"
},
"Change to 200": {
"Type": "Pass",
"Result": {"statuscode" :"200"} ,
"Next": "Call API"
},
"OK": {
"Type": "Pass",
"Result": "The request has succeeded.",
"End": true
}
}
}
d. Fai clic sul pulsante di aggiornamento accanto al pannello del flusso di lavoro visivo affinché Step Functions crei un diagramma per la macchina a stato che corrisponda al flusso di lavoro appena progettato. Dopo avere esaminato il flusso di lavoro visivo, fai clic su Create state machine (Crea macchina a stati).
Fase 4. Verifica il flusso di lavoro di gestione errori
Per verificare il flusso di lavoro di gestione errori, invocherai la macchina a stati per chiamare l’API simulata fornendo il codice di errore come input.
b. Viene visualizzata una nuova finestra di dialogo di esecuzione dove puoi inserire l’input per la macchina a stati. Interpreterai il ruolo dell’API e fornirai il codice di errore che vogliamo che l’API simulata restituisca. Sostituisci il testo esistente con il codice seguente, quindi scegli Start execution (Avvia esecuzione):
{
"statuscode": "200"
}
c. Nella schermata Execution details (Dettagli esecuzione), fai clic su Input per vedere l'input fornito sulla macchina a stati. Quindi, fai clic su Output per visualizzare il risultato dell’esecuzione della macchina a stati. Puoi vedere che il flusso di lavoro ha interpretato lo statuscode 200 come una chiamata API andata a buon fine.
d. In Visual workflow (Flusso di lavoro visivo), puoi vedere il percorso di esecuzione di ogni esecuzione, visualizzata in verde nel flusso di lavoro. Fai clic sullo stato dell’Attività "Call API" ed espandi quindi i campi Input e Output nella schermata Step details (Dettagli fase).
Puoi vedere che questo stato dell’Attività ha invocato correttamente la funzione Lambda API simulata con l’input fornito e ha acquisito l’output di tale funzione Lambda, “200 OK”.
e. Quindi, fai clic sullo stato dell’Attività “OK” nel flusso di lavoro visivo. In Step details (Dettagli fase) puoi vedere che l’output della fase precedente (lo stato dell’Attività “Call API”) è stato passato come input a questa fase. Lo stato OK è uno stato Pass, che ha semplicemente passato il proprio input al proprio output, senza eseguire lavoro. Gli stati Pass sono utili nella creazione e nell’esecuzione del debug della macchine a stati.
Fase 5. Ispeziona l’esecuzione della macchina a stati
c. Nella sezione Execution event history (Cronologia eventi di esecuzione), espandi ogni fase di esecuzione per confermare che il flusso di lavoro si sia comportato come previsto. Era previsto che questa esecuzione non andasse a buon fine, quindi non allarmarti. Noterai che:
- Step Functions hanno acquisito il tuo input
- Quell’input è stato passato allo stato dell’attività Call API
- Lo stato dell’attività Call API ha chiamato la MockAPIFunction utilizzando quell’input
- MockAPIFunction eseguita
- MockAPIFunction non riuscita con ServerUnavailableException
- L’istruzione Catch nello stato dell’attività Call API ha rilevato tale eccezione
- L’istruzione Catch non è andata a buon fine nel flusso di lavoro
- La macchina a stati ha completato la propria esecuzione
d. Quindi, simulerai un’eccezione 429. Scorri fino alla parte superiore della schermata Execution details (Dettagli esecuzione) e fai clic su MyAPIStateMachine. Fai clic su Start execution (Avvia esecuzione), fornisci l’input seguente e fai clic su Start execution (Avvia esecuzione):
{
"statuscode": "429"
}
e. Ora ispezionerai il comportamento Retry del tuo flusso di lavoro. Nella sezione Execution event history (Cronologia eventi di esecuzione), espandi ogni fase di esecuzione ancora una volta per confermare che Step Functions ha tentato di chiamare la funzione MockAPILambda altre due volte, entrambe le quali non sono andate a buon fine. A quel punto, il flusso di lavoro è passato dallo stato Wait allo stato Try Later (mostrato nell’immagine a destra) nella speranza che l’API sia stata soltanto temporaneamente non reattiva.
Quindi, lo stato Wait ha adottato la forza bruta per modificare il codice di risposta in 200 e il tuo flusso di lavoro ha completato correttamente l’esecuzione. Probabilmente questo non sarebbe il modo in cui gestiresti un’eccezione 429 in un’applicazione reale ma cerchiamo di semplificare le cose ai fini del tutorial.
f. Esegui un’altra istanza del tuo flusso di lavoro e, questa volta, fornisci una risposta API casuale che non viene gestita dalla tua macchina a stati:
{
"statuscode": "999"
}
Ispeziona di nuovo l’esecuzione utilizzando la Execution event history (Cronologia eventi di esecuzione). Al completamento, fai clic ancora una volta su MyAPIStateMachine. Nel riquadro Executions (Esecuzioni), puoi visualizzare la cronologia di tutte le esecuzioni del tuo flusso di lavoro e accedervi singolarmente, come preferisci.
Fase 6. Interruzione delle risorse
In questa fase interromperai le tue risorse relative ad AWS Step Functions e AWS Lambda.
Importante: l'interruzione delle risorse che non vengono utilizzate attivamente consente di ridurre i costi e costituisce una best practice. La mancata interruzione delle risorse potrebbe determinare costi non desiderati.
b. Nella finestra State machines (Macchine a stati), fai clic su MyAPIStateMachine e seleziona Delete (Elimina). Conferma l'azione selezionando Delete state machine (Elimina macchina a stati) nella finestra di dialogo. La tua macchina a stati verrà eliminata entro uno o due minuti, dopo che Step Functions avrà confermato che qualsiasi esecuzione in corso è stata completata.
Complimenti!
Hai utilizzato AWS Step Functions e AWS Lambda per creare un flusso di lavoro di gestione degli errori per un’API di rete. Con AWS Lambda, puoi eseguire codice per qualsiasi tipo di applicazione o servizio di back-end, senza bisogno di amministrazione. Una volta caricato il codice, Lambda si prende carico delle azioni necessarie per eseguirlo e ricalibrarne le risorse con la massima disponibilità.
Unendo AWS Step Functions e AWS Lambda facilita l'orchestrazione delle funzioni di AWS Lambda per le applicazioni serverless. Step Functions consente di controllare i flussi di lavoro complessi utilizzando le funzioni Lambda senza l’applicazione sottostante per gestire e orchestrare lo stato. Puoi anche utilizzare Step Functions per l'orchestrazione di microservizi utilizzando risorse di calcolo quali Amazon EC2 e Amazon ECS.