Invoca funzione AWS Lambda - Amazon Simple Storage Service

Invoca funzione AWS Lambda

Richiamo della funzione AWS Lambda avvia le funzioni AWS Lambda per eseguire operazioni personalizzate sugli oggetti elencati in un manifest. Questa sezione descrive come creare una funzione Lambda da utilizzare con le operazioni in batch Amazon S3 e come creare un processo per richiamare la funzione. Il processo di S3 Batch Operations utilizza l'operazione LambdaInvoke per eseguire una funzione Lambda su ogni oggetto elencato in un manifest.

Puoi lavorare con le operazioni in batch S3 per Lambda utilizzando la AWS Management Console, AWS Command Line Interface (AWS CLI), gli SDK AWS o le API REST. Per ulteriori informazioni sull'utilizzo di Lambda, consulta Nozioni di base su AWS Lambda nella Guida per Developer di AWS Lambda.

Le sezioni seguenti spiegano come iniziare a utilizzare le operazioni in batch S3 con Lambda.

Utilizzo di Lambda con le operazioni in batch Amazon S3

Durante l'utilizzo delle operazioni in batch S3 con AWS Lambda, occorre creare nuove funzioni Lambda specifiche da utilizzare con le operazioni in batch S3. Non puoi riutilizzare funzioni basate su eventi Amazon S3 esistenti con le operazioni in batch S3. Le funzioni evento possono solo ricevere messaggi, non possono restituirli. Le funzioni Lambda utilizzate con le operazioni in batch S3 devono accettare e restituire messaggi. Per ulteriori informazioni sull'utilizzo di Lambda con eventi Amazon S3, consulta Utilizzo di AWS Lambda con Amazon S3 nella Guida per Developer AWS Lambda.

Devi creare un processo di operazioni in batch Amazon S3 che richiama la funzione Lambda. Il processo esegue la stessa funzione Lambda su tutti gli oggetti elencati nel manifest. Puoi controllare quali versioni della funzione Lambda utilizzare durante l'elaborazione degli oggetti nel manifest. Le operazioni in batch S3 supportno Amazon Resource Name (ARN) non qualificati, alias e versioni specifiche. Per ulteriori informazioni, consulta Introduzione al controllo delle versioni di AWS Lambda nella Guida per Developer di AWS Lambda.

Se fornisci il processo di operazioni in batch Amazon S3 con una funzione ARN che utilizza un alias o il qualificatore $LATEST e aggiorni la versione cui questi puntano, le operazioni in batch S3 iniziano a chiamare la nuova versione della funzione Lambda. Ciò può essere utile quando desideri aggiornare la parte di funzionalità durante un processo di grandi dimensioni. Se non vuoi che le operazioni in batch S3 modifichino la versione utilizzata, fornisci la versione specifica nel parametro FunctionARN durante la creazione del processo.

Codici di risposta e dei risultati

Le operazioni in batch S3 richiedono due livelli di codice dalle funzioni Lambda. Il primo è il codice di risposta per l'intera richiesta, il secondo è il codice dei risultati per ogni singola attività. La tabella seguente contiene i codici di risposta.

Codice di risposta Descrizione
Succeeded L'attività si è conclusa normalmente. Se hai richiesto un rapporto di completamento del processo, la stringa di risultato dell'attività viene inclusa nel rapporto.
TemporaryFailure Nell'attività si è verificato un errore temporaneo e verrà reindirizzata prima del completamento del processo. La stringa risultante viene ignorata. Se questo è l'ultimo reindirizzamento, il messaggio di errore viene incluso nel rapporto finale.
PermanentFailure Nell'attività si è verificato un errore permanente. Se hai richiesto un rapporto di completamento del processo, l'attività viene contrassegnata come Failed e include la stringa del messaggio di errore. Le stringhe risultanti da attività non riuscite vengono ignorate.

Creazione di una funzione Lambda da utilizzare con le operazioni in batch S3

In questa sezione sono fornite delle autorizzazioni AWS Identity and Access Management (IAM) di esempio da utilizzare con la funzione Lambda. Contiene anche una funzione Lambda di esempio da utilizzare con le operazioni in batch S3. Se non hai mai creato una funzione Lambda, consulta Tutorial: utilizzo di AWS Lambda con Amazon S3 nella Guida per Developer di AWS Lambda.

Devi creare funzioni Lambda specifiche da utilizzare con le operazioni in batch S3. Non puoi riutilizzare funzioni Lambda basate su eventi Amazon S3 esistenti. Il motivo è che le funzioni Lambda utilizzate per le operazioni in batch S3 devono accettare e restituire campi dati speciali.

Importante

Le funzioni AWS Lambda scritte in Java accettano le interfacce handler RequestHandler o RequestStreamHandler. Tuttavia, per supportare il formato di richiesta e risposta di operazioni in batch S3, AWS Lambda richiede l'interfaccia RequestStreamHandler per la serializzazione e la deserializzazione personalizzate di una richiesta e una risposta. Questa interfaccia permette a Lambda di passare oggetti InputStream e OutputStream al metodo Java handleRequest.

Assicurati di specificare l'interfaccia RequestStreamHandler quando utilizzi funzioni Lambda con le operazioni in batch S3. Se utilizzi un'interfaccia RequestHandler, il processo batch non riuscirà restituendo il messaggio "Invalid JSON returned in Lambda payload" (JSON non valido restituito nel payload Lambda) nel report di completamento.

Per ulteriori informazioni, consulta Interfacce Handler nella Guida per l'utente di AWS Lambda.

Autorizzazioni IAM di esempio

Di seguito sono riportati alcuni esempi delle autorizzazioni IAM necessarie per utilizzare una funzione Lambda con le operazioni in batch S3.

Esempio – Policy di trust delle operazioni in batch S3

Di seguito è riportato un esempio di policy di trust che puoi utilizzare per il ruolo IAM in Batch Operations. Questo ruolo IAM viene specificato quando crei il processo e concede a Batch Operations l'autorizzazione per assumere il ruolo IAM.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "batchoperations.s3.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Esempio – Policy IAM Lambda

Di seguito è riportato un esempio di policy IAM che fornisce alle operazioni in batch S3 l'autorizzazione per richiamare la funzione Lambda e leggere il manifest di input.

{ "Version": "2012-10-17", "Statement": [ { "Sid": "BatchOperationsLambdaPolicy", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:PutObject", "lambda:InvokeFunction" ], "Resource": "*" } ] }

Richiesta e risposta di esempio

Questa sezione fornisce esempi di richiesta e risposta per la funzione Lambda.

Esempio Request

Di seguito è riportato un esempio JSON di richiesta per la funzione Lambda.

{ "invocationSchemaVersion": "1.0", "invocationId": "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo", "job": { "id": "f3cc4f60-61f6-4a2b-8a21-d07600c373ce" }, "tasks": [ { "taskId": "dGFza2lkZ29lc2hlcmUK", "s3Key": "customerImage1.jpg", "s3VersionId": "1", "s3BucketArn": "arn:aws:s3:us-east-1:0123456788:awsexamplebucket1" } ] }
Esempio Response

Di seguito è riportato un esempio JSON di risposta per la funzione Lambda.

{ "invocationSchemaVersion": "1.0", "treatMissingKeysAs" : "PermanentFailure", "invocationId" : "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo", "results": [ { "taskId": "dGFza2lkZ29lc2hlcmUK", "resultCode": "Succeeded", "resultString": "[\"Mary Major", \"John Stiles\"]" } ] }

Funzione Lambda di esempio per le operazioni in batch S3

Nell’esempio seguente Python Lambda rimuove un contrassegno di eliminazione da un oggetto con versione.

Come mostrato nell'esempio, le chiavi di operazioni in batch S3 sono codificate in formato URL. Per utilizzare Amazon S3 con altri servizi AWS, è importante che l'URL decodifichi la chiave che viene passata dalle operazioni in batch S3.

import logging from urllib import parse import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) logger.setLevel('INFO') s3 = boto3.client('s3') def lambda_handler(event, context): """ Removes a delete marker from the specified versioned object. :param event: The S3 batch event that contains the ID of the delete marker to remove. :param context: Context about the event. :return: A result structure that Amazon S3 uses to interpret the result of the operation. When the result code is TemporaryFailure, S3 retries the operation. """ # Parse job parameters from Amazon S3 batch operations invocation_id = event['invocationId'] invocation_schema_version = event['invocationSchemaVersion'] results = [] result_code = None result_string = None task = event['tasks'][0] task_id = task['taskId'] try: obj_key = parse.unquote(task['s3Key'], encoding='utf-8') obj_version_id = task['s3VersionId'] bucket_name = task['s3BucketArn'].split(':')[-1] logger.info("Got task: remove delete marker %s from object %s.", obj_version_id, obj_key) try: # If this call does not raise an error, the object version is not a delete # marker and should not be deleted. response = s3.head_object( Bucket=bucket_name, Key=obj_key, VersionId=obj_version_id) result_code = 'PermanentFailure' result_string = f"Object {obj_key}, ID {obj_version_id} is not " \ f"a delete marker." logger.debug(response) logger.warning(result_string) except ClientError as error: delete_marker = error.response['ResponseMetadata']['HTTPHeaders'] \ .get('x-amz-delete-marker', 'false') if delete_marker == 'true': logger.info("Object %s, version %s is a delete marker.", obj_key, obj_version_id) try: s3.delete_object( Bucket=bucket_name, Key=obj_key, VersionId=obj_version_id) result_code = 'Succeeded' result_string = f"Successfully removed delete marker " \ f"{obj_version_id} from object {obj_key}." logger.info(result_string) except ClientError as error: # Mark request timeout as a temporary failure so it will be retried. if error.response['Error']['Code'] == 'RequestTimeout': result_code = 'TemporaryFailure' result_string = f"Attempt to remove delete marker from " \ f"object {obj_key} timed out." logger.info(result_string) else: raise else: raise ValueError(f"The x-amz-delete-marker header is either not " f"present or is not 'true'.") except Exception as error: # Mark all other exceptions as permanent failures. result_code = 'PermanentFailure' result_string = str(error) logger.exception(error) finally: results.append({ 'taskId': task_id, 'resultCode': result_code, 'resultString': result_string }) return { 'invocationSchemaVersion': invocation_schema_version, 'treatMissingKeysAs': 'PermanentFailure', 'invocationId': invocation_id, 'results': results }

Creazione di un processo di operazioni in batch Amazon S3 che richiama una funzione Lambda

Quando crei un processo di operazioni in batch Amazon S3 per richiamare una funzione Lambda, devi fornire gli elementi seguenti:

  • ARN della funzione Lambda, che può includere l'alias della funzione o un numero specifico di versione

  • Ruolo IAM con l'autorizzazione per richiamare la funzione

  • Il parametro dell'operazione LambdaInvokeFunction

Per ulteriori informazioni sulla creazione di un processo di operazioni in batch Amazon S3, consulta Creazione di un processo di operazioni in batch S3 e Operazioni supportate dalle operazioni in batch S3.

L'esempio seguente crea un processo di operazioni in batch S3 che richiama una funzione Lambda tramite la AWS CLI.

aws s3control create-job --account-id <AccountID> --operation '{"LambdaInvoke": { "FunctionArn": "arn:aws:lambda:Region:AccountID:function:LambdaFunctionName" } }' --manifest '{"Spec":{"Format":"S3BatchOperations_CSV_20180820","Fields":["Bucket","Key"]},"Location":{"ObjectArn":"arn:aws:s3:::ManifestLocation","ETag":"ManifestETag"}}' --report '{"Bucket":"arn:aws:s3:::awsexamplebucket1","Format":"Report_CSV_20180820","Enabled":true,"Prefix":"ReportPrefix","ReportScope":"AllTasks"}' --priority 2 --role-arn arn:aws:iam::AccountID:role/BatchOperationsRole --region Region --description “Lambda Function"

Aggiunta di informazioni a livello di attività nei manifest Lambda

Quando utilizzi le funzioni AWS Lambda con le operazioni in batch S3, potrebbero essere utili dei dati aggiuntivi a ciascuna attività/chiave su cui si opera. Ad esempio, ti potrebbe far comodo disporre di una chiave dell'oggetto di origine e di una nuova chiave dell'oggetto. La funzione Lambda può quindi copiare la chiave di origine in un nuovo bucket S3 con un nuovo nome. Per impostazione predefinita, le operazioni in batch Amazon S3 ti permettono di specificare solo il bucket di destinazione e un elenco di chiavi di origine nel manifest di input nel processo. Di seguito viene descritto come includere dati aggiuntivi nel manifest per poter eseguire funzioni Lambda più complesse.

Per specificare i parametri per chiave nel manifest delle operazioni in batch S3 da utilizzare nel codice della funzione Lambda, utilizza il formato JSON con codifica in formato URL seguente. Il campo key viene passato alla funzione Lambda come se fosse una chiave oggetto Amazon S3. Tuttavia, può essere interpretato dalla funzione Lambda come contenente altri valori o più chiavi, come mostrato di seguito.

Nota

Il numero massimo di caratteri per il campo key nel manifest è 1.024.

Esempio – Manifest in cui le chiavi Amazon S3 vengono sostituite con stringhe JSON

Alle operazioni in batch S3 deve essere fornita la versione con codifica in formato URL.

my-bucket,{"origKey": "object1key", "newKey": "newObject1Key"} my-bucket,{"origKey": "object2key", "newKey": "newObject2Key"} my-bucket,{"origKey": "object3key", "newKey": "newObject3Key"}
Esempio – Manifest con codifica in formato URL

Alle operazioni in batch S3 deve essere fornita questa versione con codifica in formato URL. La versione senza codifica URL non funziona.

my-bucket,%7B%22origKey%22%3A%20%22object1key%22%2C%20%22newKey%22%3A%20%22newObject1Key%22%7D my-bucket,%7B%22origKey%22%3A%20%22object2key%22%2C%20%22newKey%22%3A%20%22newObject2Key%22%7D my-bucket,%7B%22origKey%22%3A%20%22object3key%22%2C%20%22newKey%22%3A%20%22newObject3Key%22%7D
Esempio – Funzione Lambda con formato manifest che scrive i risultati nel report del processo

Questa funzione Lambda mostra come analizzare un’attività delimitata da pipe codificata nel manifest di operazioni in batch S3. L'attività indica quale operazione di revisione viene applicata all'oggetto specificato.

import logging from urllib import parse import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) logger.setLevel('INFO') s3 = boto3.resource('s3') def lambda_handler(event, context): """ Applies the specified revision to the specified object. :param event: The Amazon S3 batch event that contains the ID of the object to revise and the revision type to apply. :param context: Context about the event. :return: A result structure that Amazon S3 uses to interpret the result of the operation. """ # Parse job parameters from Amazon S3 batch operations invocation_id = event['invocationId'] invocation_schema_version = event['invocationSchemaVersion'] results = [] result_code = None result_string = None task = event['tasks'][0] task_id = task['taskId'] # The revision type is packed with the object key as a pipe-delimited string. obj_key, revision = \ parse.unquote(task['s3Key'], encoding='utf-8').split('|') bucket_name = task['s3BucketArn'].split(':')[-1] logger.info("Got task: apply revision %s to %s.", revision, obj_key) try: stanza_obj = s3.Bucket(bucket_name).Object(obj_key) stanza = stanza_obj.get()['Body'].read().decode('utf-8') if revision == 'lower': stanza = stanza.lower() elif revision == 'upper': stanza = stanza.upper() elif revision == 'reverse': stanza = stanza[::-1] elif revision == 'delete': pass else: raise TypeError(f"Can't handle revision type '{revision}'.") if revision == 'delete': stanza_obj.delete() result_string = f"Deleted stanza {stanza_obj.key}." else: stanza_obj.put(Body=bytes(stanza, 'utf-8')) result_string = f"Applied revision type '{revision}' to " \ f"stanza {stanza_obj.key}." logger.info(result_string) result_code = 'Succeeded' except ClientError as error: if error.response['Error']['Code'] == 'NoSuchKey': result_code = 'Succeeded' result_string = f"Stanza {obj_key} not found, assuming it was deleted " \ f"in an earlier revision." logger.info(result_string) else: result_code = 'PermanentFailure' result_string = f"Got exception when applying revision type '{revision}' " \ f"to {obj_key}: {error}." logger.exception(result_string) finally: results.append({ 'taskId': task_id, 'resultCode': result_code, 'resultString': result_string }) return { 'invocationSchemaVersion': invocation_schema_version, 'treatMissingKeysAs': 'PermanentFailure', 'invocationId': invocation_id, 'results': results }