使用Node和Node-gyp

时间:2016-06-23 09:16:58

标签: c node.js amazon-web-services aws-lambda

我有一个用NodeJS编写的AWS Lambda,调用过程非常简单

NODEJS - > NodeModule(CPP) - > Extern C Function,此设置使用node-gyp编译。 您可以在https://drive.google.com/open?id=0B-2d-CuY5fkwS3lwdE96R1V6NEk

处查看整个代码

CPP节点模块调用C中的一个运行循环的函数。并在C函数的范围内增加一个变量,在C代码的主范围内增加另一个变量。

在本地运行此代码时。循环递增,两个变量都达到11,正如预期的那样运行它。但是当您在AWS Lambda中运行相同的代码时,每次调用都会有某种“内存”。并且一般范围内的变量(未被重置)正在增加,以11,22,33等的倍数增加。

重复一遍,这绝不会在本地发生,变量总是在11。 你可以通过运行来构建 1. node-gyp clean configure build 2.节点app.js(用于本地运行)

Index.js适用于AWS Lambda

我真的无法解释这种行为? Lambda可以使用某种上下文或某种“内存”或缓存吗?

我为此做了一个Open API网关。 (随意刷新并查看“记忆”)。

https://koj2yva6z9.execute-api.us-east-1.amazonaws.com/dev/testLambdaCache

此行为有时会不一致,有时计数会重置。或者您可以通过上传新的AWS lambda代码重置。

对这种奇怪行为的任何想法都表示赞赏。

app.js(用于本地测试)

var addon = require('./build/Release/addon');
console.log(addon.testCache());
console.log(" addon method completed");

index.js(在lambda中使用)

console.log('Loading function');

exports.handler = (event, context, callback) => {

    var addon = require('./build/Release/addon');
    var returnvalue=addon.testCache();
    console.log(returnvalue);
    console.log(" addon method completed");
    callback(null, "success::"+returnvalue);
}

base.cc(C代码包装)

#include <node.h>
#include <iostream>
#include <stdlib.h>
#include<string>
#include<cstring>

using namespace std;

extern "C" char* testCache();

namespace demo {

    using v8::FunctionCallbackInfo;
    using v8::HandleScope;
    using v8::Isolate;
    using v8::Local;
    using v8::Object;
    using v8::String;
    using v8::Value;
    using v8::Exception;

    void Method(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = args.GetIsolate();
        cout << "C++ method started\n";
        char *returnStrings=NULL;
        returnStrings= testCache();
        args.GetReturnValue().Set(String::NewFromUtf8(isolate,  returnStrings ));
    }

    void init(Local<Object> exports) {
        NODE_SET_METHOD(exports, "testCache", Method);
    }

    NODE_MODULE(addon, init)

}  

decoder.c(运行循环的c代码)

int tmpCounter=0;


char* testCache()
{
    int counter=0;
    printf("Local counter --> %d  Global Counter --> %d\n",counter,tmpCounter); 
    for(int i=0;i <10; i++)
    {
        counter = counter +1;
        tmpCounter = tmpCounter +1;
        //sleep(1);
    }
    printf("Local counter --> %d  Global Counter --> %d\n",counter,tmpCounter); 

    counter=counter+1;
    tmpCounter=tmpCounter+1;

    char strCounter[100];
    char strTmpCounter[100];
    snprintf(strCounter, 16, "%d", counter);

    snprintf(strTmpCounter, 16, "%d", tmpCounter);

    char *returnString=NULL;
    returnString=malloc(1000);

    strcat(returnString, "Count:");
    strcat(returnString, strCounter);
    strcat(returnString, " TmpCount:");
    strcat(returnString, strTmpCounter);
    strcat(returnString, "\0");
    printf("%s\n",returnString);
    fflush(stdout);
    return returnString;

}

2 个答案:

答案 0 :(得分:1)

  

Lambda可以使用某种上下文或某种“内存”或缓存吗?

我不会说它是“可用的”,因为它是可预测的或一致的,因为你不应该围绕它设计,但是,是的,有容器重用。

要看到这一点:

创建一个uuid或随机数或类似的东西,并将其存储在处理程序之外的全局变量中。然后,在处理程序内部,记录它。您将看到相同的进程或进程组(由uuid标识)可能(但不一定)处理后续请求的时间。

  

假设您的功能完成,并且一段时间过去了,那么您再次调用它。 Lambda可能会再次创建一个新的容器[...]

     

但是,如果您没有更改代码并且没有太多时间,Lambda可能会重复使用以前的容器。这为双方提供了一些性能优势:Lambda可以跳过nodejs语言初始化,并且可以跳过代码中的初始化。如果重复使用沙箱,您上次写入/ tmp的文件仍然存在。

     

https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/

答案 1 :(得分:0)

strcattestCache的所有来电均为UB,因为malloc内存不存在。

使用calloc

更改它
returnString=calloc(1, 1000);

或使用sprintf

更改第一个
sprintf(returnString, "Count:");

此外strcat(returnString, "\0");无用

最后总是检查malloc&amp;朋友返回值,例如

if (returnString != NULL)
{
   // OK, MEMORY ALLOCATED
}
else
{
   // ERROR
}