无服务器Lambda调用Lambda。没有错误,但响应是空的

时间:2018-08-04 16:53:56

标签: amazon-web-services aws-lambda serverless-framework

现在,如果我们要创建一个lambda函数来调用另一个函数,则可以使用AWS StepFunction。 但是现在,我需要支持在StepFunctions之前编写的生产中的代码。 因此,我需要了解其工作原理。我试图创建一个非常简单的lambda来调用另一个RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{QUERY_STRING} ^var [NC] RewriteRule ^([^/]+)$ /link.php?id=$1 [L,QSA] 的lambda函数。

我有以下serverless.yml

AWS-SDk

这是handler.js:

service: lambdaCallLambda

provider:
  name: aws
  runtime: nodejs6.10

functions:
  hello:
    handler: handler.hello
  funcOne:
    handler: handler.funcOne  
  funcTwo:
    handler: handler.funcTwo

#Must install aws-sdk.  #npm install --save aws-sdk

部署'use strict'; //https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html var Lambda = require('aws-sdk/clients/lambda'); module.exports.hello = (event, context, callback) => { const response = { statusCode: 200, body: JSON.stringify({ message: 'hello', input: event, }), }; callback(null, response); }; module.exports.funcOne = (event, context, callback) => { var text=''; var i = 0; for (i = 0; i < 5; i++) { text += "The number is " + i + "\n"; } console.log(text); //https://docs.aws.amazon.com/general/latest/gr/rande.html const lambda = new Lambda({ region: 'us-east-1' }); console.log('control 3'); /* https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property To invoke a Lambda function This operation invokes a Lambda function https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html Payload - JSON that you want to provide to your Lambda function as input. */ var params = { ClientContext: "lambdaCallLambda", FunctionName: "lambdaCallLambda-dev-funcOne", InvocationType: "Event", LogType: "Tail", Payload: '{"jsonKey2":123}', Qualifier: "1" }; lambda.invoke(params, function(err, data) { if (err){ console.log('control error\n'); console.log(err, err.stack); // an error occurred } else{ console.log('control OK\n'); console.log(data); // successful response } /* data = { FunctionError: "", LogResult: "", Payload: <Binary String>, StatusCode: 123 } */ }); }; module.exports.funcTwo = async (event, context) => { return 2; //return '{"funcTwo":20000}'; //console.log("funcTwo = " + event); }; 并致电sls deploy后,我得到以下2个输出:

本地funcOne

sls invoke local --function funcOne

在AWS中远程调用: Serverless: INVOKING INVOKE The number is 0 The number is 1 The number is 2 The number is 3 The number is 4 control 3 control OK { StatusCode: 202, Payload: '' }

sls invoke  --function funcOne

有人知道帽子在这里发生吗?特别是对于第一种情况,我没有任何错误。 这就是我得到的from the documentation

{
    "errorMessage": "Unexpected token (",
    "errorType": "SyntaxError",
    "stackTrace": [
        "                               ^",
        "SyntaxError: Unexpected token (",
        "createScript (vm.js:56:10)",
        "Object.runInThisContext (vm.js:97:10)",
        "Module._compile (module.js:542:28)",
        "Object.Module._extensions..js (module.js:579:10)",
        "Module.load (module.js:487:32)",
        "tryModuleLoad (module.js:446:12)",
        "Function.Module._load (module.js:438:3)",
        "Module.require (module.js:497:17)",
        "require (internal/module.js:20:19)"
    ]
}

  Error --------------------------------------------------

  Invoked function failed

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information -----------------------------
     OS:                     linux
     Node Version:           8.11.3
     Serverless Version:     1.29.2

更新

在EduardoDíaz建议之后- 我将lambda.invoke更改为:

Parameters:

err (Error) — the error object returned from the request. Set to null if the request is successful.
data (Object) — the de-serialized data returned from the request. Set to null if a request error occurs. The data object has the following properties:
Status — (Integer)
It will be 202 upon success.

这就是我从本地和远程获得的:

lambda.invoke({
    FunctionName: 'lambdaCallLambda-dev-funcOne',
    Payload: JSON.stringify(event, null, 2)
  }, function(error, data) {
    if (error) {
      console.log('control ErrorFoncOne\n');
      context.done('error', error);
    }
    if(data.Payload){
     console.log('control SuccessFoncOne\n'); 
     context.succeed(data)
    }
  });

这是一个SyntaxError。某处有一个“(”。 我发现了另一个开发者,发生了相同的错误here

注意:

CloudWatch中没有错误日志

3 个答案:

答案 0 :(得分:0)

尝试在有效负载中发送事件:

public class Program
{
  public static async Task Main(string[] args)
  {
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
      var services = scope.ServiceProvider;
      Console.WriteLine(services.GetService<IConfiguration>().GetConnectionString("DefaultConnection"));
      try
      {
        var context = services.GetRequiredService<PdContext>();
        var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();

        var dbInitializerLogger = services.GetRequiredService<ILogger<DbInitializer>>();
        await DbInitializer.Initialize(context, userManager, roleManager, dbInitializerLogger);
      }
      catch (Exception ex)
      {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred while migrating the database.");
      }
    }

    host.Run();
  }

  public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .Build();
}

答案 1 :(得分:0)

我强烈怀疑此问题根源于您对funcTwo的处理程序签名:

module.exports.funcTwo = async (event, context) => { 

NodeJS 6.10不支持async / await。无论出于何种原因,Node总是抱怨async令牌之后的令牌 。如果您不使用粗箭头功能:

module.exports.funcTwo = async function(event, context) {

节点将抱怨:Unexpected token function

选项

  • 将功能部署到NodeJS 8.10。
  • 摆脱处理程序签名中的async关键字。
  • 使用构建工具(如serverless-webpack)将功能转换为ES6(或更低版本)。

注意:如果您坚持使用6.10运行时,我想您应该做类似context.succeed(2);callback(null, 2);而不是return 2;的事情。只需使用return语句确实即可在8.10上运行。

答案 2 :(得分:0)

我发现了问题。我们需要lamdda.invoke方法中的播放负载中的JSON.stringfy。不需要额外的参数。根据文档,只有JSON。

lambda.invoke({
      FunctionName: 'lambdaCallLambda-dev-funcTwo',
      Payload: JSON.stringify({"jsonKey2":i})
...

AWS documentation for playload中,我们有:

Payload
JSON that you want to provide to your Lambda function as input.

注意:

功能前面的异步

lambda.invoke({
      FunctionName: 'lambdaCallLambda-dev-funcTwo',
      Payload: JSON.stringify({"jsonKey2":i})
    }, async function(error, data) { ...

module.exports.funcTwo = async(event, context, callback) => { ...

给我这个输出:

Loop nb=1

Loop nb=2

Loop nb=3

Loop nb=4

Loop nb=5

{"message":"hello from funcTwo","event":{"jsonKey2":3}}
{"message":"hello from funcTwo","event":{"jsonKey2":2}}
{"message":"hello from funcTwo","event":{"jsonKey2":1}}
{"message":"hello from funcTwo","event":{"jsonKey2":5}}
{"message":"hello from funcTwo","event":{"jsonKey2":4}}

虽然缺少 async 可以给我:

Loop nb=1

Loop nb=2

Loop nb=3

Loop nb=4

Loop nb=5

{"message":"hello from funcTwo","event":{"jsonKey2":1}}
{"message":"hello from funcTwo","event":{"jsonKey2":2}}
{"message":"hello from funcTwo","event":{"jsonKey2":3}}
{"message":"hello from funcTwo","event":{"jsonKey2":4}}
{"message":"hello from funcTwo","event":{"jsonKey2":5}}

我将共享handle.js代码,以防万一其他人需要它:

'use strict';


//https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html
var Lambda = require('aws-sdk/clients/lambda');


module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'hello',
      input: event,
    }),
  };

  callback(null, response);
};

/*

    https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property
    To invoke a Lambda function
    This operation invokes a Lambda function

    https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
    Payload - JSON that you want to provide to your Lambda function as input.

    Serverless Framework: Lambdas Invoking Lambdas
    https://lorenstewart.me/2017/10/02/serverless-framework-lambdas-invoking-lambdas/

    How to escape async/await hell
    https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c

    Iterating a Loop Using Lambda
    https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-create-iterate-pattern-section.html


    AWS Lambda “Process exited before completing request”
    https://stackoverflow.com/questions/31627950/aws-lambda-process-exited-before-completing-request


    Class: AWS.Lambda
    https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#constructor-property
    Invoke
    https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax


    Programming Model(Node.js)
    https://docs.aws.amazon.com/lambda/latest/dg/programming-model.html


    AWS Lambda Examples
    https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/lambda-examples.html

  */



//The event is a file inserted in S3. This function funcOne reads the file and loop trough all quantities of products.
//Invoking a lamda function funcTwo for each process in the loop.
module.exports.funcOne = (event, context, callback) => { 

  //https://docs.aws.amazon.com/general/latest/gr/rande.html
  const lambda = new Lambda({
    region: 'us-east-1'
  });

  //Loop
  //nbProducts = loop trough the products JSON list in S3    
  var nbProducts=5;  
  for (let i = 1; i <= nbProducts; i++) {
    console.log('Loop nb='+i+'\n');

  lambda.invoke({
      FunctionName: 'lambdaCallLambda-dev-funcTwo',
      Payload: JSON.stringify({"jsonKey2":i})
    }, async function(error, data) {
      if (error) {
        //console.log('control ErrorFoncOne\n');
        context.done('error', error);
      }
      if(data.Payload){
       //console.log('control SuccessFoncOne\n'); 
       console.log(data.Payload);
       //context.succeed(data)
      }
    });
  }  
};


module.exports.funcTwo = async(event, context, callback) => {
   callback(null, { message: 'hello from funcTwo', event });
};