Kann eine AWS Lambda-Funktion eine andere aufrufen?

320

Ich habe 2 Lambda-Funktionen - eine, die ein Angebot erstellt, und eine, die ein Angebot in eine Bestellung umwandelt. Ich möchte, dass die Order Lambda-Funktion die Quote-Funktion aufruft, um das Angebot neu zu generieren, anstatt es nur von einem nicht vertrauenswürdigen Client zu erhalten.

Ich habe überall gesucht, wo ich mir vorstellen kann - aber ich kann nicht sehen, wie ich die Funktionen verketten oder aufrufen würde ... das gibt es sicherlich!

Silber
quelle
1
Ich erreiche hier, aber warum können Sie sich nicht auf das AWS JavaScript SDK in der ersten Lambda-Funktion verlassen, einen AWS.Lambda- Client erstellen und die zweite Funktion aufrufen ?
Devonlazarus
Es ist das, was ich versuchen wollte - aber ich war mir nicht ganz sicher, wie ich es anstellen sollte, da es keine Beispiele dafür gab, wie man es von einer anderen Lambda-Funktion aus macht.
Silber
1
Anscheinend können Sie eine Lambda-Funktion auch über HTTP aufrufen .
Devonlazarus
4
und noch eine Idee, Sie könnten sie über SNS
verketten
6
Eine andere gebräuchliche Alternative, die hier nicht erwähnt wird, sind Schrittfunktionen oder SWF.
lebryant

Antworten:

365

Ich habe einen Weg gefunden mit dem 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)
  }
});

Sie finden das Dokument hier: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html

Nicolas Grenié
quelle
28
Die Verwendung von SNS ist wahrscheinlich der bessere Ansatz, aber dies ist die richtige Antwort.
Silber
29
Ich könnte mich irren, aber ich denke, weil der Aufruf synchron ist, wartet das erste Lambda darauf, dass das zweite Lambda beendet wird. Daher fallen Gebühren an, während beide Lambdas ausgeführt werden. Bei Verwendung von SNS sollte das erste Lambda beendet werden und das zweite Lambda unabhängig ausgeführt werden können.
Dev
81
Ich konnte dies dank des InvocationType: 'Event'Parameters zum Laufen bringen (nach FunctionNameund hinzufügen Payload). Aus den Dokumenten: "Sie können optional eine asynchrone Ausführung anfordern, indem Sie Event als InvocationType angeben." Bei der asynchronen Ausführung wird die Rückruffunktion zuverlässig aufgerufen, ohne jedoch warten zu müssen, bis das aufgerufene Lambda die Ausführung beendet hat.
Alessandro
24
Beachten Sie, dass die Rolle der aufrufenden Lambda-Funktion eine IAM-Richtlinie enthalten muss AWSLambdaRole. Sie können der vorhandenen Richtlinie Ihrer Rolle auch das folgende Anweisungsobjekt hinzufügen: '{"Effekt": "Zulassen", "Aktion": ["Lambda: InvokeFunction"], "Ressource": ["*"]} `
Bob Arlof
4
Tatsächlich hat AWS die StepFunctions veröffentlicht, mit denen Sie mehrere Lambda aufrufen können, ohne ein Lambda von einem anderen Lambda aus aufrufen zu müssen. Der erste "wartet" nicht auf den zweiten
Sebastien H.
116

Sie sollten Ihre Lambda functionsVia verketten SNS. Dieser Ansatz bietet eine gute Leistung, Latenz und Skalierbarkeit bei minimalem Aufwand.

Ihr erster Lambdaveröffentlicht Nachrichten an Sie SNS Topicund der zweite Lambdahat dieses Thema abonniert. Sobald Nachrichten im Thema eintreffen, wird der zweite Lambdamit der Nachricht als Eingabeparameter ausgeführt.

Siehe Aufrufen von Lambda-Funktionen mithilfe von Amazon SNS-Benachrichtigungen .

Sie können diesen Ansatz auch verwenden, um kontenübergreifende Lambda-Funktionen über SNS aufzurufen .

kixorz
quelle
2
Kinesis ist vielleicht etwas komplizierter, aber wenn Sie nach einer robusteren Lösung suchen, ist sie möglicherweise eine gute Option für Sie. Außerdem speichert SNS die eingehenden Ereignisse nicht wie Kinesis.
Kixorz
7
"Sie sollten Ihre Lambda-Funktionen über SNS verketten" - können Sie dies mit Beweisen / Links zu Dokumenten unterstützen? Ich sehe, wie beide Methoden funktionieren würden, ich wäre daran interessiert, einige Meinungen / bestimmte Aussagen zu sehen, von denen eine die bevorzugte ist
Claude
30
Dies ist eine gute Idee, wenn Sie es asynchron benötigen. Wenn Ihre erste Lambda-Funktion jedoch den vom zweiten Lambda zurückgegebenen Wert benötigt , müssen Sie die Lambdas verketten und die erste Lambda-Funktion muss die zweite Lambda-Funktion direkt aufrufen.
Noel Llevares
3
Ich würde die Verwendung von SNS nicht empfehlen. Sie können einfach die asynchrone Aufruf-API für die Lambda-Funktion verwenden - kein Grund, SNS zu verwenden, es sei denn, Sie möchten mehrere Abonnenten benachrichtigen und nicht nur eine andere Lambda-Funktion auslösen.
6
Beachten Sie, dass SNS keine Zustellgarantie hat, sodass Sie die Nachricht möglicherweise auslösen, aber möglicherweise nicht ankommen.
Bart Van Remortele
79

Hier ist ein Beispielcode für 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)

Übrigens müssten Sie Ihrer Lambda-Rolle auch eine solche Richtlinie hinzufügen

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }
Blueskin
quelle
Die Dokumentation scheint darauf hinzudeuten, dass die Nutzlast JSON sein muss. Ist es möglich, Binärdaten zu senden?
mbatchkarov
2
Ich bevorzuge diese Methode auch, aber sie hat einen Fehler. Sie müssen das datetime.now()in einen String konvertieren (oder irgendwie damit umgehen). Andernfalls erhalten Sie den Fehlerdatetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable
John C
Ist es möglich, in der Rolle des ersten Lambda restriktiver zu sein? Dh, um es auf das Aufrufen bestimmter Funktionen und nicht auf alle zu beschränken?
Phil
@Phil vielleicht kann das Feld "Ressource" so eingestellt werden, dass nur ein bestimmter Satz von Funktionen erlaubt ist, ich bin mir jedoch nicht ganz sicher
Blueskin
2
Das InvocationTypesollte sein : RequestResponse. Um die Antwort von dem Lambda zu erhalten, das Sie aufrufen möchten.
Ambigus9
31

Seit diese Frage gestellt wurde, hat Amazon Step Functions ( https://aws.amazon.com/step-functions/ ) veröffentlicht.

Eines der Grundprinzipien von AWS Lambda ist, dass Sie sich mehr auf die Geschäftslogik und weniger auf die Anwendungslogik konzentrieren können, die alles miteinander verbindet. Mit Step-Funktionen können Sie komplexe Interaktionen zwischen Funktionen orchestrieren, ohne dafür den Code schreiben zu müssen.

Dustinnoe
quelle
12

Diese Lösung wird mit boto3 und Python durchgeführt:

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
Trilok Nagvenkar
quelle
2
InvocationType Wählen Sie eine der folgenden Optionen. RequestResponse (Standard) - Ruft die Funktion synchron auf. Lassen Sie die Verbindung offen, bis die Funktion eine Antwort zurückgibt oder eine Zeitüberschreitung auftritt. Ereignis - Ruft die Funktion asynchron auf. Senden Sie Ereignisse, die mehrmals fehlschlagen, an die Dead-Letter-Warteschlange der Funktion (falls konfiguriert). DryRun - Überprüfen Sie die Parameterwerte und stellen Sie sicher, dass der Benutzer oder die Rolle die Berechtigung zum Aufrufen der Funktion hat.
Trilok Nagvenkar
11

Ich wollte SNS ausschneiden, bis ich dies in den Lambda-Client-Dokumenten (Java-Version) sah :

Client für den Zugriff auf AWS Lambda. Alle mit diesem Client getätigten Serviceanrufe werden blockiert und erst nach Abschluss des Serviceabrufs zurückgegeben.

SNS hat also einen offensichtlichen Vorteil: Es ist asynchron. Ihr Lambda wartet nicht auf den Abschluss des nachfolgenden Lambda.

Ben Iggulden
quelle
17
InvocationType = 'Event' macht es asynchron. docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/…
Ankit
3
@Ankit, das sollte die ausgewählte Antwort sein, ich wurde irregeführt zu glauben, dass die Verwendung von SNS die einzige Möglichkeit war, einen asynchronen Aufruf durchzuführen, da niemand mit diesen Informationen antwortete.
@Ankit Kennen Sie ein Beispiel mit InvocationType = 'Event', aber von Java anstelle von JavaScript? Es gibt eine
Menge
SNS fügt noch Kosten für seine Nutzung hinzu
Sebastien H.
1
@SebastienH. Für SNS, das Lambda aufruft, fallen keine Kosten an. aws.amazon.com/sns/pricing
fabdouglas
8

Amazon hat 2016 in AWS Lambda Stufenfunktionen eingeführt. Ich denke, jetzt ist es bequemer, die Stufenfunktion zu verwenden, da sie wirklich einfach zu verwenden ist. Sie können eine Zustandsmaschine mit zwei Lambda-Funktionen erstellen:

  • ein Angebot erstellen
  • verwandelt ein Angebot in eine Bestellung

Sie können dies einfach wie folgt tun:

Hier können Sie den ersten Status für die Erstellung eines Angebots und einen weiteren für die Reihenfolge festlegen

{
  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
    }
  }
}

Mit den Steps-Funktionen können Sie ganz einfach mehrere Lambda-Funktionen schreiben und nacheinander oder parallel ausführen. Sie können weitere Informationen über Lambda - Schritte - Funktionen erhalten hier: Steps Funktionen

Sunil Kapil
quelle
5

Ich arbeite mit der Antwort zur Verfügung gestellt von Blueskin aber ich konnte die Payload Antwort nicht lesen , weil die InvocationType = ‚Ereignis‘ ist async , so dass ich als InvocationType geändert = ‚Requestresponse‘ und jetzt funktioniert alles gut.

Antonio
quelle
5

In Java können wir Folgendes tun:

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

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

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

Hier ist Payload Ihr String- Java-Objekt, das als Json-Objekt an ein anderes Lambda übergeben werden muss, falls Sie einige Informationen vom Aufruf von Lambda an das aufgerufene Lambda übergeben müssen.

Suyash
quelle
2

Sie können direkt Lambda - Funktion aufrufen (zumindest über Java) unter Verwendung von AWSLambdaClientwie in dem Blog der AWS Post .

Neil
quelle
2

Ich habe das gleiche Problem, aber die von mir implementierte Lambda-Funktion fügt einen Eintrag in DynamoDB ein, sodass meine Lösung DynamoDB-Trigger verwendet.

Ich lasse die DB für jede Einfügung / Aktualisierung in der Tabelle eine Lambda-Funktion aufrufen, wodurch die Implementierung von zwei Lambda-Funktionen getrennt wird.

Die Dokumentation finden Sie hier: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html

Hier ist eine Anleitung: https://aws.amazon.com/blogs/aws/dynamodb-update-triggers-streams-lambda-cross-region-replication-app/

Lewen
quelle
1

Eine Art Kreisverkehrslösung, aber ich rufe nur den API-Endpunkt für meine Lambda-Funktionen auf, wenn ich sie verketten muss. Auf diese Weise können Sie beim Codieren entscheiden, ob sie asynchron sein sollen oder nicht.

Wenn Sie keine POST-Anforderung einrichten möchten, können Sie einfach eine einfache GET-Anforderung mit einigen oder gar keinen Abfragezeichenfolgenparametern einrichten, um die Ereignisübergabe zu vereinfachen.

- Bearbeiten -

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

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

Anselm
quelle
1
Dies scheint viel weniger Kreisverkehr als SNS, aber dann habe ich nicht viel Erfahrung mit SNS
Brandon
Können Sie den Code freigeben, der zum Aufrufen eines API-Endpunkts innerhalb eines Lambda erforderlich ist?
Glenn
@Glenn es ist nur eine Ajax-Anfrage. Kennzeichnen Sie Ihre Parameter, die Sie als Abfrageparameter benötigen. Siehe: docs.aws.amazon.com/apigateway/api-reference/… und docs.aws.amazon.com/lambda/latest/dg/…
Anselm
4
Ein weiteres Problem besteht darin, dass das Durchlaufen des API-Gateways im Vergleich zum Aufrufen einer anderen Lambda-Funktion relativ teuer ist. Eine 128-MB-Funktion, die mindestens 100 ms lang ausgeführt wird, kostet 0,21 USD pro 1 Million Anrufe, während das API-Gateway 3,50 USD pro 1 Million kostet. Wenn Sie länger laufen oder mehr RAM verwenden, müssen Sie natürlich die 21 Cent multiplizieren, aber dennoch sind 3,50 USD pro Million sehr teuer. (Diese Preise waren ab August 2017
Patrick Chu
1

Andere wiesen darauf hin, SQS- und Schrittfunktionen zu verwenden. Beide Lösungen verursachen jedoch zusätzliche Kosten. Schritt Funktionszustandsübergänge sind angeblich sehr teuer.

AWS Lambda bietet eine Wiederholungslogik. Wo es 3 mal was versucht. Ich bin nicht sicher, ob dies noch gültig ist, wenn Sie es über die API auslösen.

nnrales
quelle
0

Hier ist das Python-Beispiel für den Aufruf einer anderen Lambda-Funktion, die ihre Antwort erhält. Es gibt zwei Aufrufarten 'RequestResponse' und 'Event' . Verwenden Sie 'RequestResponse', wenn Sie die Antwort der Lambda-Funktion erhalten möchten, und verwenden Sie 'Event', um die Lambda-Funktion asynchron aufzurufen. Es stehen also sowohl asynchrone als auch synchrone Möglichkeiten zur Verfügung.

    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)
lalit gangwar
quelle
-1

Sie können die AWS_REGION-Umgebung festlegen.

assert(process.env.AWS_REGION, 'Missing AWS_REGION env (eg. ap-northeast-1)');
const aws = require('aws-sdk');
const lambda = new aws.Lambda();
Hojin
quelle