Une fonction AWS Lambda peut-elle en appeler une autre

320

J'ai 2 fonctions Lambda - une qui produit un devis et une qui transforme un devis en commande. J'aimerais que la fonction Order lambda appelle la fonction Quote pour régénérer le devis, plutôt que de simplement le recevoir d'un client non fiable.

J'ai regardé partout où je peux penser - mais je ne vois pas comment j'allais enchaîner ou appeler les fonctions ... ça existe sûrement!

argent
la source
1
J'arrive ici, mais pourquoi ne pourriez-vous pas dépendre du SDK JavaScript AWS dans la première fonction Lambda, créer un client AWS.Lambda et appeler la deuxième fonction?
devonlazarus
C'est ce que j'allais essayer - mais je ne savais pas trop comment m'y prendre, car il n'y avait aucun exemple de le faire à partir d'une autre fonction Lambda.
Silver
1
apparemment, vous pouvez également appeler une fonction Lambda via HTTP .
devonlazarus
4
et une autre idée, vous pouvez les chaîner via SNS , ce qui est probablement la voie que
j'opterais pour
6
Les autres fonctions courantes non mentionnées ici sont les fonctions pas à pas ou SWF.
lebryant

Réponses:

365

J'ai trouvé un moyen d'utiliser le 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)
  }
});

Vous pouvez trouver le document ici: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html

Nicolas Grenié
la source
28
L'utilisation de SNS est probablement la meilleure approche, mais c'est la bonne réponse.
Silver
29
Je peux me tromper, mais je pense que parce que l'invocation est synchrone, le premier lambda attend que le deuxième lambda se termine, vous accumulerez donc des charges pendant que les deux lambdas fonctionnent. en utilisant SNS, le premier lambda doit se terminer et permettre au deuxième lambda de s'exécuter indépendamment.
dev
81
J'ai pu faire fonctionner cela grâce au InvocationType: 'Event'paramètre (ajoutez-le après FunctionNameet Payload). De la documentation: "Vous pouvez éventuellement demander une exécution asynchrone en spécifiant Event comme InvocationType." Avec une exécution asynchrone, la fonction de rappel sera appelée de manière fiable, mais sans avoir à attendre la fin de l'exécution du lambda invoqué.
Alessandro
25
Notez que le rôle de la fonction lambda appelante doit inclure une stratégie IAM AWSLambdaRole. Vous pouvez également ajouter l'objet d'instruction suivant à la stratégie existante de votre rôle: '{"Effect": "Allow", "Action": ["lambda: InvokeFunction"], "Resource": ["*"]} `
Bob Arlof
4
En fait, AWS a publié les StepFunctions qui vous permettent d'appeler plusieurs lambda sans avoir à appeler un lambda à partir d'un autre lambda, de sorte que pour ie. le premier n'attend pas la fin du second
Sebastien H.
116

Vous devez enchaîner votre Lambda functionsvia SNS. Cette approche offre de bonnes performances, une latence et une évolutivité pour un effort minimal.

Votre premier Lambdapublie des messages sur votre SNS Topicet le second Lambdaest abonné à ce sujet. Dès que des messages arrivent dans le sujet, le second Lambdaest exécuté avec le message comme paramètre d'entrée.

Voir Appel de fonctions Lambda à l'aide de notifications Amazon SNS .

Vous pouvez également utiliser cette approche pour appeler des fonctions Lambda inter-comptes via SNS .

kixorz
la source
2
Kinesis peut être un peu plus compliqué, mais si vous cherchez une solution plus robuste, cela peut être une bonne option pour vous. De plus, SNS ne stocke pas les événements entrants, Kinesis le fait.
kixorz
7
"Vous devez chaîner vos fonctions Lambda via SNS" - pouvez-vous soutenir cela avec des preuves / liens vers des documents? Je vois comment les deux méthodes fonctionneraient, je serais intéressé de voir quelques opinions / déclarations définitives sur laquelle on est le préféré
Claude
30
C'est une bonne idée si vous avez besoin qu'elle soit asynchrone. Mais si votre première fonction lambda a besoin de la valeur renvoyée par la seconde lambda, vous devez chaîner les lambdas et demander à la première fonction lambda d'appeler directement la deuxième fonction lambda.
Noel Llevares
3
Je ne recommanderais pas d'utiliser SNS. Vous pouvez simplement utiliser l'API d'appel asynchrone pour la fonction lambda - aucune raison d'utiliser SNS à moins que vous ne souhaitiez notifier plusieurs abonnés et pas simplement déclencher une autre fonction lambda.
6
Gardez à l'esprit que SNS n'a pas de garantie de livraison, vous pourriez donc déclencher le message, mais il pourrait ne pas arriver.
Bart Van Remortele
79

voici un exemple de code pour 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)

Btw, vous devez également ajouter une stratégie comme celle-ci à votre rôle lambda

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }
blueskin
la source
La documentation semble suggérer que la charge utile doit être JSON. Est-il possible d'envoyer des données binaires?
mbatchkarov
2
Je préfère également cette méthode, mais elle a un problème. Vous devrez convertir le datetime.now()en une chaîne (ou le gérer d'une manière ou d'une autre). Sinon, vous obtenez l'erreurdatetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable
John C
Est-il possible d'être plus restrictif dans le rôle du premier lambda? C'est-à-dire, le lier à l'invocation de fonctions spécifiques , plutôt que toutes et toutes?
Phil
@Phil peut-être que le champ "Ressource" peut être défini pour n'autoriser qu'un ensemble spécifique de fonctions, je ne suis pas tout à fait sûr cependant
blueskin
2
Le InvocationTypedevrait être: RequestResponse. Pour obtenir la réponse du lambda que vous essayez d'invoquer.
ambigus9
31

Depuis que cette question a été posée, Amazon a publié Step Functions ( https://aws.amazon.com/step-functions/ ).

L'un des principes fondamentaux derrière AWS Lambda est que vous pouvez vous concentrer davantage sur la logique métier et moins sur la logique d'application qui relie tout cela. Les fonctions d'étape vous permettent d'orchestrer des interactions complexes entre les fonctions sans avoir à écrire le code pour le faire.

dustinnoe
la source
12

Cette solution se fait en utilisant boto3 et 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
Trilok Nagvenkar
la source
2
InvocationType Choisissez parmi les options suivantes. RequestResponse (par défaut) - Appelez la fonction de manière synchrone. Gardez la connexion ouverte jusqu'à ce que la fonction renvoie une réponse ou expire. Événement - Appelez la fonction de manière asynchrone. Envoyez des événements qui échouent plusieurs fois à la file d'attente de lettres mortes de la fonction (si elle est configurée). DryRun - Validez les valeurs des paramètres et vérifiez que l'utilisateur ou le rôle est autorisé à appeler la fonction.
Trilok Nagvenkar
11

Je cherchais à couper SNS jusqu'à ce que je voie cela dans les documents du client Lambda (version Java) :

Client pour accéder à AWS Lambda. Tous les appels de service effectués à l'aide de ce client sont bloquants et ne reviendront pas avant la fin de l'appel de service.

SNS a donc un avantage évident: il est asynchrone. Votre lambda n'attendra pas la fin de la lambda suivante.

Ben Iggulden
la source
17
InvocationType = 'Event' le rend asynchrone. docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/…
Ankit
3
@Ankit qui devrait être la réponse choisie, j'ai été induit en erreur en pensant que l'utilisation de SNS était le seul moyen de faire un appel asynchrone car personne n'a répondu avec ces informations.
@Ankit connaissez-vous un exemple utilisant InvocationType = 'Event' mais de Java au lieu de JavaScript? Il y a une tonne de documentation Java, mais pas autant d'exemples que JavaScript
Talador12
SNS ajoute encore des coûts pour son utilisation
Sebastien H.
1
@SebastienH. Il n'y a aucun coût pour que SNS appelle Lambda. aws.amazon.com/sns/pricing
fabdouglas
8

Amazon a introduit les fonctions étapes dans AWS lambda en 2016. Je pense qu'il est désormais plus pratique d'utiliser la fonction étapes car il est vraiment facile de les utiliser. Vous pouvez créer une machine à états avec deux fonctions lambda comme:

  • produire un devis
  • transforme un devis en commande

Vous pouvez facilement le faire comme ci-dessous:

Ici, vous pouvez avoir un premier état pour produire un devis et un autre pour se transformer en ordre

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

Les fonctions Steps facilitent l'écriture de plusieurs fonctions lambda et leur exécution en séquence ou en parallèle. Vous pouvez obtenir plus d'informations sur les fonctions d'étapes lambda ici: Fonctions d'étapes

Sunil Kapil
la source
5

Je travaillais avec la réponse fournie par blueskin mais je n'ai pas pu lire la réponse Payload car l' InvocationType = 'Event' est asynchrone , j'ai donc changé en InvocationType = 'RequestResponse' et maintenant tout fonctionne bien.

antonio
la source
5

En java, nous pouvons faire comme suit:

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

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

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

Ici, la charge utile est votre objet java stratifié qui doit être transmis en tant qu'objet Json à un autre lambda au cas où vous auriez besoin de transmettre certaines informations de l'appel de lambda à lambda appelé.

Suyash
la source
2

Vous pouvez appeler la fonction lambda directement (au moins via Java) en utilisant AWSLambdaClientcomme décrit dans le blog « AWS après .

Neil
la source
2

J'ai le même problème mais la fonction Lambda que j'implémente insérera une entrée dans DynamoDB, donc ma solution utilise les déclencheurs DynamoDB.

Je fais invoquer la base de données une fonction Lambda pour chaque insertion / mise à jour dans le tableau, donc cela sépare l'implémentation de deux fonctions Lambda.

La documentation est ici: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html

Voici une procédure pas à pas guidée: https://aws.amazon.com/blogs/aws/dynamodb-update-triggers-streams-lambda-cross-region-replication-app/

Lewen
la source
1

Une sorte de solution détournée mais j'appelle simplement le point de terminaison API de pour mes fonctions lambda lorsque j'ai besoin de les enchaîner. Cela vous permet de décider lors du codage si vous souhaitez qu'ils soient asynchrones ou non.

Dans le cas où vous ne souhaitez pas configurer une demande POST, vous pouvez simplement configurer une simple demande GET avec quelques paramètres de chaîne de requête, voire aucun, pour un passage facile des événements.

-- Éditer --

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

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

Anselme
la source
1
cela semble beaucoup moins détourné que SNS, mais je n'ai pas beaucoup d'expérience avec SNS
Brandon
Pouvez-vous partager le code nécessaire pour appeler un point de terminaison API à partir d'un lambda?
Glenn
@Glenn c'est juste une requête ajax. Marquez vos paramètres comme paramètres de requête. Voir: docs.aws.amazon.com/apigateway/api-reference/… et docs.aws.amazon.com/lambda/latest/dg/…
Anselm
4
Un autre problème est que passer par API Gateway est relativement cher par rapport à appeler une autre fonction Lambda. Une fonction de 128 Mo exécutée pendant 100 ms (le minimum) coûte 0,21 $ pour 1 million d'appels, tandis que la passerelle API coûte 3,50 $ pour 1 million. Évidemment, si vous courez plus de temps ou si vous utilisez plus de RAM, vous devrez multiplier les 21 cents, mais quand même, 3,50 $ par million est vraiment cher. (Ces prix étaient en vigueur en août 2017)
Patrick Chu
1

D'autres ont souligné l'utilisation de SQS et des fonctions pas à pas. Mais ces deux solutions ajoutent un coût supplémentaire. Les transitions d'état de fonction d'étape sont censées être très coûteuses.

AWS lambda propose une logique de nouvelle tentative. Où il essaie quelque chose 3 fois. Je ne sais pas si cela est toujours valide lorsque vous le déclenchez en utilisant l'API.

nnrales
la source
0

Voici l'exemple python d'appeler une autre fonction lambda et obtient sa réponse. Il existe deux types d'appel «RequestResponse» et «Event» . Utilisez «RequestResponse» si vous souhaitez obtenir la réponse de la fonction lambda et utilisez «Event» pour appeler la fonction lambda de manière asynchrone. Les deux modes asynchrones et synchrones sont donc disponibles.

    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
la source
-1

Vous pouvez définir l'environnement 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();
hojin
la source