Una funzione AWS Lambda può chiamarne un'altra


320

Ho 2 funzioni Lambda - una che produce un preventivo e una che trasforma un preventivo in un ordine. Vorrei che la funzione Ordine lambda chiamasse la funzione Preventivo per rigenerare il preventivo, piuttosto che riceverlo da un client non attendibile.

Ho guardato ovunque mi venga in mente - ma non riesco a capire come farei per concatenare o chiamare le funzioni ... sicuramente esiste!


1
Sto raggiungendo qui, ma perché non potevi dipendere dall'SDK AWS JavaScript nella prima funzione Lambda, creare un client AWS.Lambda e invocare la seconda funzione?
Devonlazarus,

È quello che stavo per provare, ma non ero del tutto sicuro di come procedere, poiché non c'erano esempi di farlo da un'altra funzione Lambda.
Silver,

1
apparentemente puoi anche invocare una funzione Lambda tramite HTTP .
Devonlazarus,

4
e un'altra idea, potresti incatenarli attraverso SNS , che è probabilmente il modo in cui andrei come strategia più scalabile
Devonlazarus,

6
Altre alternative comuni non menzionate qui sono Step Functions o SWF.
Lebryant,

Risposte:


365

Ho trovato un modo usando il aws-sdk.

var aws = require('aws-sdk');
var lambda = new aws.Lambda({
  region: 'us-west-2' //change to your region
});

lambda.invoke({
  FunctionName: 'name_of_your_lambda_function',
  Payload: JSON.stringify(event, null, 2) // pass params
}, function(error, data) {
  if (error) {
    context.done('error', error);
  }
  if(data.Payload){
   context.succeed(data.Payload)
  }
});

Puoi trovare il documento qui: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html


28
L'uso di SNS è probabilmente l'approccio migliore, ma questa è la risposta corretta.
Argento

29
potrei sbagliarmi, ma penso che, poiché l'invocazione è sincrona, la prima lambda attende che la seconda lambda si interrompa, quindi accumulerai addebiti mentre entrambe le lambda sono in esecuzione. usando SNS, il primo lambda dovrebbe terminare e consentire l'esecuzione del secondo lambda in modo indipendente.
dev

81
Sono stato in grado di farlo funzionare grazie al InvocationType: 'Event'parametro (aggiungilo dopo FunctionNamee Payload). Dai documenti: "Puoi facoltativamente richiedere l'esecuzione asincrona specificando Event come InvocationType." Con l'esecuzione asincrona, la funzione di callback verrà chiamata in modo affidabile, ma senza dover attendere il completamento dell'esecuzione della lambda invocata.
Alessandro,

25
Si noti che il ruolo della funzione lambda chiamante deve includere la politica IAM AWSLambdaRole. In alternativa, puoi aggiungere il seguente oggetto istruzione al criterio esistente del tuo ruolo: '{"Effetto": "Consenti", "Azione": ["lambda: InvokeFunction"], "Resource": ["*"]} `
Bob Arlof,

4
In realtà AWS ha rilasciato le StepFunctions che ti consentono di chiamare più lambda senza dover invocare una lambda da un'altra lambda, in modo che, ad esempio. il primo non "aspetta" che il secondo finisca
Sebastien H.

116

Dovresti incatenare il tuo Lambda functionsvia SNS. Questo approccio offre buone prestazioni, latenza e scalabilità per il minimo sforzo.

Il tuo primo Lambdapubblica messaggi sul tuo SNS Topice il secondo Lambdaè iscritto a questo argomento. Non appena arrivano messaggi nell'argomento, il secondo Lambdaviene eseguito con il messaggio come parametro di input.

Consulta Invocare le funzioni Lambda utilizzando le notifiche di Amazon SNS .

È inoltre possibile utilizzare questo approccio per richiamare le funzioni Lambda tra account tramite SNS .


2
Kinesis potrebbe essere un po 'più complicato, ma se stai cercando una soluzione più solida, allora potrebbe essere una buona opzione per te. Inoltre, SNS non memorizza gli eventi in arrivo, lo fa Kinesis.
Kixorz,

7
"Dovresti concatenare le tue funzioni Lambda tramite SNS" - puoi supportarlo con prove / collegamenti a documenti? Vedo come funzionerebbero entrambi i metodi, sarei interessato a vedere alcune opinioni / affermazioni certe su quale è il preferito
Claude

30
Questa è una buona idea se ne hai bisogno per essere asincrona. Ma se la tua prima funzione lambda richiede il valore restituito dalla seconda lambda, devi concatenare le lambda e fare in modo che la prima funzione lambda invochi direttamente la seconda funzione lambda.
Noel Llevares il

3
Non consiglierei di usare SNS. Puoi semplicemente utilizzare l'API di invocazione asincrona per la funzione lambda, nessun motivo per utilizzare SNS a meno che tu non voglia notificare più abbonati e non solo attivare un'altra funzione lambda.

6
Tieni presente che SNS non ha la garanzia di consegna, quindi potresti licenziare il messaggio ma potrebbe non arrivare.
Bart Van Remortele,

79

ecco un codice di esempio per Python,

from boto3 import client as boto3_client
from datetime import datetime
import json

lambda_client = boto3_client('lambda')

def lambda_handler(event, context):
    msg = {"key":"new_invocation", "at": datetime.now()}
    invoke_response = lambda_client.invoke(FunctionName="another_lambda_",
                                           InvocationType='Event',
                                           Payload=json.dumps(msg))
    print(invoke_response)

A proposito, dovresti aggiungere una politica come questa anche al tuo ruolo lambda

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }

La documentazione sembra suggerire che il payload deve essere JSON. È possibile inviare dati binari?
mbatchkarov,

2
Preferisco anche questo metodo, ma ha un problema tecnico. Dovrai convertirlo datetime.now()in una stringa (o gestirlo in qualche modo). Altrimenti, ricevi l'erroredatetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable
John C

È possibile essere più restrittivi nel ruolo della prima lambda? Cioè, per legarlo all'invocazione di funzioni specifiche , piuttosto che a tutte?
Phil

@Phil forse il campo "Resource" può essere impostato per consentire solo un set specifico di funzioni, non ne sono del tutto sicuro
blueskin

2
Il InvocationTypedovrebbe essere: RequestResponse. Per ottenere la risposta dalla lambda che si sta tentando di invocare.
ambigus9

31

Da quando questa domanda è stata posta, Amazon ha rilasciato Step Functions ( https://aws.amazon.com/step-functions/ ).

Uno dei principi alla base di AWS Lambda è che puoi concentrarti di più sulla logica di business e meno sulla logica di applicazione che lega tutto. Le funzioni di passaggio consentono di orchestrare interazioni complesse tra le funzioni senza dover scrivere il codice per farlo.


12

Questa soluzione è fatta usando boto3 e Python:

import boto3
import json

invokeLambda = boto3.client('lambda', region_name='eu-west-1')

def lambda_handler(event, context):
    invokeLambda.invoke(FunctionName = 'function_name', InvocationType = 'RequestResponse', Payload = json.dumps(event))

    return True

2
InvocationType Scegliere tra le seguenti opzioni. RequestResponse (impostazione predefinita): richiama la funzione in modo sincrono. Mantenere la connessione aperta fino a quando la funzione non restituisce una risposta o scade. Evento: richiama la funzione in modo asincrono. Invia eventi che non riescono più volte alla coda di messaggi non instradabili della funzione (se configurata). DryRun: convalida i valori dei parametri e verifica che l'utente o il ruolo disponga dell'autorizzazione per richiamare la funzione.
Trilok Nagvenkar,

11

Stavo cercando di eliminare SNS fino a quando non ho visto questo nei documenti del client Lambda (versione Java) :

Client per l'accesso ad AWS Lambda. Tutte le chiamate di servizio effettuate utilizzando questo client sono bloccate e non verranno restituite fino al completamento della chiamata di servizio.

Quindi SNS ha un evidente vantaggio: è asincrono. Il tuo lambda non aspetterà il completamento del lambda successivo.


17
InvocationType = 'Event' lo rende asincrono. docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/…
Ankit

3
@Ankit che dovrebbe essere la risposta selezionata, sono stato indotto in errore a credere che usare SNS fosse l'unico modo per fare una chiamata asincrona perché nessuno ha risposto con queste informazioni.

@Ankit conosci un esempio usando InvocationType = 'Event' ma da Java invece di JavaScript? C'è una tonnellata di documentazione Java, ma non tanti esempi quanti JavaScript
Talador12,

SNS aggiunge ancora i costi per il suo utilizzo
Sebastien H.

1
@SebastienH. Non vi è alcun costo per SNS che invoca Lambda. aws.amazon.com/sns/pricing
fabdouglas,

8

Amazon ha introdotto le funzioni di passi in AWS lambda nel 2016. Penso, ora è più conveniente usare la funzione di passi in quanto è davvero facile usarli. Puoi costruire una macchina a stati con due funzioni lambda come:

  • per produrre un preventivo
  • trasforma un preventivo in un ordine

Puoi farlo facilmente come di seguito:

Qui puoi avere il primo stato per produrre un preventivo e un altro per trasformarlo in ordine

{
  Comment: "Produce a quote and turns into an order",
  StartAt: "ProduceQuote",
  States: {
    ProduceQuote: {
      "Type": Task,
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      "next": TurnsToOrder
    }
    TurnsToOrder: {
      Type: Task,
      Resource: "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      end: true
    }
  }
}

Le funzioni Step rendono davvero semplice scrivere più funzioni lambda ed eseguirle in sequenza o in parallelo. Puoi ottenere maggiori informazioni sulle funzioni dei passi lambda qui: Funzioni dei passi


5

Stavo lavorando con la risposta fornita da blueskin ma non riuscivo a leggere la risposta del payload perché InvocationType = 'Event' è asincrono , quindi ho cambiato come InvocationType = 'RequestResponse' e ora funziona tutto bene.


5

In Java, possiamo fare come segue:

AWSLambdaAsync awsLambdaAsync = AWSLambdaAsyncClientBuilder.standard().withRegion("us-east-1").build();

InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.withFunctionName("youLambdaFunctionNameToCall").withPayload(payload);

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

Qui, payload è l' oggetto java con stringhe che deve essere passato come oggetto Json a un'altra lambda nel caso in cui sia necessario passare alcune informazioni dalla chiamata lambda alla chiamata lambda.



2

Puoi invocare la funzione lambda direttamente (almeno tramite Java) usando AWSLambdaClientcome descritto nel post sul blog di AWS .


2

Sto riscontrando lo stesso problema, ma la funzione Lambda che implemento inserirà una voce in DynamoDB, quindi la mia soluzione utilizza Trigger DynamoDB.

Faccio in modo che il DB invochi una funzione Lambda per ogni inserimento / aggiornamento nella tabella, quindi questo separa l'implementazione di due funzioni Lambda.

La documentazione è qui: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html

Ecco una guida guidata: https://aws.amazon.com/blogs/aws/dynamodb-update-triggers-streams-lambda-cross-region-replication-app/


1

Una specie di soluzione rotonda, ma chiamo l' endpoint API per le mie funzioni lambda quando devo incatenarle. Ciò consente di decidere durante la codifica se si desidera che siano asincroni o meno.

Nel caso in cui non si desideri impostare una richiesta POST, è sufficiente impostare una semplice richiesta GET con una coppia, o nessuna, parametri della stringa di query per passare facilmente gli eventi.

-- Modificare --

Vedi: https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/

e: http://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https-example.html


1
sembra molto meno rotonda di SNS, ma poi non ho molta esperienza con SNS
Brandon,

Puoi condividere il codice necessario per chiamare un endpoint API dall'interno di una lambda?
Glenn,

@Glenn è solo una richiesta Ajax. Contrassegnare i parametri necessari come parametri di query. Vedi: docs.aws.amazon.com/apigateway/api-reference/… e docs.aws.amazon.com/lambda/latest/dg/…
Anselm

4
Un altro problema è che passare attraverso API Gateway è relativamente costoso rispetto a chiamare un'altra funzione Lambda. Una funzione da 128 MB in esecuzione per 100 ms (il minimo) costa $ 0,21 per 1 milione di chiamate, mentre il gateway API costa $ 3,50 per 1 milione. Ovviamente, se corri per più tempo o usi più ram, dovresti moltiplicare i 21 centesimi, ma comunque, 3,50 $ per milione è davvero costoso. (Questi prezzi erano in vigore dall'agosto 2017)
Patrick Chu il

1

Altri hanno sottolineato di utilizzare SQS e Step Functions. Ma entrambe queste soluzioni comportano costi aggiuntivi. Le transizioni di stato della funzione Step sono presumibilmente molto costose.

AWS lambda offre una logica di nuovo tentativo. Dove prova qualcosa per 3 volte. Non sono sicuro che sia ancora valido quando lo attivi, usa l'API.


0

Ecco l'esempio python di chiamare un'altra funzione lambda e ottenere la sua risposta. Esistono due tipi di invocazione "RequestResponse" e "Event" . Utilizzare 'RequestResponse' se si desidera ottenere la risposta della funzione lambda e utilizzare 'Event' per richiamare la funzione lambda in modo asincrono. Quindi sono disponibili entrambi i modi asincrono e sincrono.

    lambda_response = lambda_client.invoke(
                FunctionName = lambda_name,
                InvocationType = 'RequestResponse',
                Payload = json.dumps(input)
                )
    resp_str = lambda_response['Payload'].read()
    response = json.loads(resp_str)

-1

È possibile impostare l'ambiente AWS_REGION.

assert(process.env.AWS_REGION, 'Missing AWS_REGION env (eg. ap-northeast-1)');
const aws = require('aws-sdk');
const lambda = new aws.Lambda();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.