Uma função do AWS Lambda pode chamar outra

320

Eu tenho 2 funções Lambda - uma que produz uma cotação e outra que transforma uma cotação em um pedido. Gostaria que a função lambda Order chame a função Quote para gerar novamente a cotação, em vez de apenas recebê-la de um cliente não confiável.

Eu procurei em todos os lugares em que consigo pensar - mas não consigo ver como eu encadear ou chamar as funções ... certamente isso existe!

Prata
fonte
1
Estou chegando aqui, mas por que você não pode depender do SDK do AWS JavaScript na primeira função Lambda, criar um cliente AWS.Lambda e chamar a segunda função?
Devonlazarus
É o que eu tentaria - mas não tinha muita certeza de como proceder, pois não havia exemplos de outra função Lambda.
Silver
1
aparentemente, você também pode chamar uma função Lambda através de HTTP .
Devonlazarus
4
e mais uma idéia, você pode acorrentar-los através do SNS , que é provavelmente a maneira que eu iria como uma estratégia mais escalável
devonlazarus
6
Outras alternativas comuns que não são mencionadas aqui são Funções de etapa ou SWF.
Lebryant #

Respostas:

365

Eu encontrei uma maneira de usar o 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)
  }
});

Você pode encontrar o documento aqui: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html

Nicolas Grenié
fonte
28
Usar o SNS é provavelmente a melhor abordagem, mas esta é a resposta correta.
Silver
29
Eu posso estar errado, mas acho que, porque a invocação é síncrona, o primeiro lambda aguarda o término do segundo lambda; portanto, você acumulará cobranças enquanto os dois lambdas estiverem em execução. usando o SNS, o primeiro lambda deve terminar e permitir que o segundo lambda seja executado independentemente.
Dev
81
Consegui fazer isso funcionar graças ao InvocationType: 'Event'parâmetro (adicione depois FunctionNamee Payload). Na documentação: "Você pode solicitar opcionalmente a execução assíncrona, especificando Event como o InvocationType". Com a execução assíncrona, a função de retorno de chamada será chamada de forma confiável, mas sem ter que esperar que o lambda chamado conclua a execução.
Alessandro
25
Observe que a função da função lambda de chamada precisa incluir a política do IAM AWSLambdaRole. Ou você pode adicionar o seguinte objeto de instrução à diretiva existente da sua função: '{"Effect": "Allow", "Action": ["lambda: InvokeFunction"], "Resource": ["*"]} `
Bob Arlof
4
Na verdade, a AWS lançou as StepFunctions, que permitem chamar vários lambda sem precisar invocar um lambda de outro lambda, de modo que, por exemplo. o primeiro não "espera" que o segundo termine
Sebastien H.
116

Você deve encadear sua Lambda functionsvia SNS. Essa abordagem fornece bom desempenho, latência e escalabilidade para um esforço mínimo.

O seu primeiro Lambdapublica mensagens para o seu SNS Topice o segundo Lambdaestá inscrito neste tópico. Assim que as mensagens chegam ao tópico, o segundo Lambdaé executado com a mensagem, como parâmetro de entrada.

Consulte Chamando funções do Lambda usando notificações do Amazon SNS .

Você também pode usar essa abordagem para invocar funções Lambda entre contas via SNS .

kixorz
fonte
2
O Kinesis pode ser um pouco mais complicado, mas se você estiver procurando uma solução mais robusta, pode ser uma boa opção para você. Além disso, o SNS não armazena os eventos recebidos, o Kinesis.
kixorz
7
"Você deve encadear suas funções do Lambda via SNS" - você pode apoiar isso com evidências / links para documentos? Eu vejo como os dois métodos funcionariam, eu estaria interessado em ver algumas opiniões / declarações definidas sobre qual é o preferido
Claude
30
É uma boa ideia se você precisar que seja assíncrono. Mas se sua primeira função lambda precisar do valor retornado da segunda lambda, você precisará encadear as lambdas e fazer com que a primeira função lambda invoque diretamente a segunda função lambda.
precisa saber é o seguinte
3
Eu não recomendaria o uso do SNS. Você pode apenas utilizar a API de chamada assíncrona para a função lambda - não há razão para usar o SNS, a menos que queira notificar vários assinantes e não apenas acionar outra função lambda.
6
Lembre-se de que o SNS não tem garantia de entrega; portanto, você pode acionar a mensagem, mas ela pode não chegar.
Bart Van Remortele
79

aqui está um código de exemplo para 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)

Aliás, você também precisará adicionar uma política como essa à sua função lambda

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }
blueskin
fonte
A documentação parece sugerir que a carga útil deve ser JSON. É possível enviar dados binários?
23417 mbmbkarkarov
2
Também prefiro esse método, mas ele tem uma falha. Você precisará converter o arquivo datetime.now()em uma string (ou manipulá-la de alguma forma). Caso contrário, você obter o errodatetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable
John C
É possível ser mais restritivo no papel da primeira lambda? Ou seja, amarrá-lo à invocação de funções específicas , ao invés de toda e qualquer coisa?
Phil Phil
@Phil talvez o campo "Recursos" pode ser definido para permitir que apenas um conjunto específico de funções, não estou completamente certo de que
Blueskin
2
O InvocationTypedeve ser: RequestResponse. Para obter a resposta do lambda que você está tentando chamar.
ambigus9
31

Desde que essa pergunta foi feita, a Amazon lançou as Step Functions ( https://aws.amazon.com/step-functions/ ).

Um dos princípios fundamentais por trás do AWS Lambda é que você pode se concentrar mais na lógica de negócios e menos na lógica do aplicativo que une tudo isso. As funções de etapa permitem orquestrar interações complexas entre funções sem precisar escrever o código para fazê-lo.

dustinnoe
fonte
12

Esta solução é feita 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
Trilok Nagvenkar
fonte
2
InvocationType Escolha entre as seguintes opções. RequestResponse (padrão) - Invoque a função de forma síncrona. Mantenha a conexão aberta até a função retornar uma resposta ou atingir o tempo limite. Evento - Invoque a função de forma assíncrona. Envie eventos que falham várias vezes para a fila de mensagens não entregues da função (se configurada). DryRun - valide os valores dos parâmetros e verifique se o usuário ou função tem permissão para chamar a função.
Trilok Nagvenkar
11

Eu estava pensando em cortar o SNS até ver isso nos documentos do cliente Lambda (versão Java) :

Cliente para acessar o AWS Lambda. Todas as chamadas de serviço feitas usando esse cliente estão bloqueando e não retornarão até que a chamada de serviço seja concluída.

Portanto, o SNS tem uma vantagem óbvia: é assíncrono. Seu lambda não esperará a conclusão do lambda subsequente.

Ben Iggulden
fonte
17
InvocationType = 'Event' torna assíncrona. docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/…
Ankit
3
@Ankit que deveria ser a resposta selecionada, fiquei enganado ao acreditar que usar o SNS era a única maneira de fazer uma chamada assíncrona porque ninguém respondeu com essas informações.
@Ankit, você conhece um exemplo usando InvocationType = 'Event', mas do Java, em vez do JavaScript? Há uma tonelada de documentação Java, mas não tão muitos exemplos como JavaScript
Talador12
SNS ainda adiciona custos para ele do uso
Sebastien H.
1
@SebastienH. Não há custo para o SNS chamar o Lambda. aws.amazon.com/sns/pricing
fabdouglas
8

A Amazon introduziu funções de etapas no AWS lambda em 2016. Acho que agora é mais conveniente usar a função de etapas, pois é muito fácil usá-las. Você pode construir uma máquina de estado com duas funções lambda como:

  • produz uma cotação
  • transforma uma cotação em um pedido

Você pode fazer isso facilmente como abaixo:

Aqui você pode ter o primeiro estado para produz uma cotação e outro para se transformar em ordem

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

As funções de etapas facilitam a gravação de várias funções lambda e a execução em sequência ou em paralelo. Você pode obter mais informações sobre as funções das etapas lambda aqui: Funções das etapas

Sunil Kapil
fonte
5

Eu estava trabalhando com a resposta fornecida pelo blueskin, mas não consegui ler a resposta da Carga útil, porque o InvocationType = 'Event' é assíncrono , então mudei como InvocationType = 'RequestResponse' e agora tudo funciona bem.

antonio
fonte
5

Em java, podemos fazer o seguinte:

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

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

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

Aqui, a carga útil é seu objeto java com string que precisa ser passado como objeto Json para outro lambda, caso você precise passar algumas informações da chamada lambda para a chamada lambda.

Suyash
fonte
2

Você pode invocar a função lambda diretamente (pelo menos via Java) usando AWSLambdaClientconforme descrito na postagem do blog da AWS .

Neil
fonte
2

Estou tendo o mesmo problema, mas a função Lambda que eu implemento insere uma entrada no DynamoDB, então minha solução usa os gatilhos do DynamoDB.

Eu faço o banco de dados invocar uma função Lambda para cada inserção / atualização na tabela, portanto, isso separa a implementação de duas funções Lambda.

A documentação está aqui: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html

Aqui está uma explicação guiada: https://aws.amazon.com/blogs/aws/dynamodb-update-triggers-streams-lambda-cross-region-replication-app/

Lewen
fonte
1

Tipo de solução rotatória, mas eu apenas chamo o ponto de extremidade da API para minhas funções lambda quando preciso encadeá-las. Isso permite que você decida durante a codificação se deseja que eles sejam assíncronos ou não.

Caso você não queira configurar uma solicitação POST, basta configurar uma solicitação GET simples com alguns ou nenhum parâmetro de string de consulta para facilitar a passagem de eventos.

- Editar -

Consulte: 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

Anselmo
fonte
1
isso parece muito menos rotunda do SNS, mas então eu não tenho muita experiência usando SNS
Brandon
Você pode compartilhar o código necessário para chamar um terminal de API de dentro de uma lambda?
Glenn
@ Glenn é apenas uma solicitação de ajax. Identifique seus parâmetros como parâmetros de consulta. Veja: docs.aws.amazon.com/apigateway/api-reference/… e docs.aws.amazon.com/lambda/latest/dg/…
Anselm
4
Outro problema é que passar pelo API Gateway é relativamente caro comparado a chamar outra função Lambda. Uma função de 128 MB em execução por 100 ms (no mínimo) custa US $ 0,21 por 1 milhão de chamadas, enquanto o API Gateway custa US $ 3,50 por 1 milhão. Obviamente, se você está correndo por mais tempo ou usa mais memória ram, teria que multiplicar os 21 centavos, mas ainda assim, US $ 3,50 por milhão é realmente caro. (Estes preços foram efetivos a partir de agosto de 2017)
Patrick Chu
1

Outros apontaram para usar SQS e Step Functions. Mas essas duas soluções adicionam custos adicionais. As transições de estado da função Step são supostamente muito caras.

O AWS lambda oferece alguma lógica de nova tentativa. Onde tenta algo por 3 vezes. Não tenho certeza se isso ainda é válido quando você o aciona usando a API.

nnrales
fonte
0

Aqui está o exemplo python de chamar outra função lambda e obtém sua resposta. Existem dois tipos de chamada 'RequestResponse' e 'Event' . Use 'RequestResponse' se desejar obter a resposta da função lambda e use 'Event' para chamar a função lambda de forma assíncrona. Portanto, os dois modos assíncrono e síncrono estão disponíveis.

    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)
gangal lalit
fonte
-1

Você pode definir o 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();
hojin
fonte