How to call one lambda from another in AWS SAM - aws-lambda

I'm writing application with multiple functions inside SAM application. I can invoke lambda function that is already deployed to AWS with code similar to AWS Lambda call Lambda but it doens't work with local functions. I tried things from https://github.com/awslabs/aws-sam-cli/issues/510 but nothing seem to work yet.
This is closest I got yet (you need sam local start-lambda --host 172.17.0.1 where host is in docker network)
var AWS = require("aws-sdk");
exports.lambdaHandler = async (event, context) => {
let lambda = new AWS.Lambda({});
if (process.env.AWS_SAM_LOCAL) {
var ep = new AWS.Endpoint("http://172.17.0.1:3001");
lambda = new AWS.Lambda({ endpoint: ep });
}
const body = await new Promise(r => {
lambda.invokeAsync(
{
FunctionName: "myFunction",
InvokeArgs: JSON.stringify({ arguments: "for other function" })
},
function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
r(data);
}
);
});
response = {
statusCode: 200,
body: JSON.stringify(body)
};
return response;
};
and at least I see some activity, but I get error in invokeAsync
PathNotFoundLocally: PathNotFoundException\n at Object.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:51:27)\n
and this error in start-lambda console
2019-12-20 16:07:02 172.17.0.7 - - [20/Dec/2019 16:07:02] "POST /2014-11-13/functions/myFunction/invoke-async/ HTTP/1.1" 404 -
UPDATE:
I was able to fix ssl error that I had in first version of this question, and it looks like it works in sync mode with lambda.invoke

It looks like this is not currently supported until https://github.com/awslabs/aws-sam-cli/pull/749 is merged

Related

NodeJS: AWS SDK V3: Not receiving any response data from lambda function

I'm trying to use the v3 javascript sdk to invoke a AWS Lambda function, and I'm having problems getting any meaningful response.
My code looks like so...
const { Lambda } = require("#aws-sdk/client-lambda");
const client = new Lambda();
const params = {
FunctionName: "MyLamdaFuncton",
Payload: JSON.stringify({ "action": "do_something" }),
InvocationType: "Event"
};
client.invoke(params)
.then((response) => {
console.log(JSON.stringify(response,null,4));
})
.catch((err) => {
console.error(err);
})
I can confirm from checking the CloudWatch logs that the lambda function works as exepcted. However this is the response I get in my NodeJS code...
{
"$metadata": {
"httpStatusCode": 202,
"requestId": "d6ba189d-9156-4f01-bd51-efe34a66fe34",
"attempts": 1,
"totalRetryDelay": 0
},
"Payload": {}
}
How do I get the actual response and status from the Lambda function?
If I change the payload above to intentionally throw an exception in my Lambda, the response in the console is still exactly the same.
update:
The Lambda function is written in Ruby. The response is returned like so...
{ statusCode: 200, body: JSON.generate(response.success?) }
where "response" is from another service it calls internally.
I've figured out what I was doing wrong. The issue was the "InvocationType". I got it working by changing to...
InvocationType: "RequestResponse"
Then I had to extract the response data like so...
const response_data = JSON.parse(new TextDecoder("utf-8").decode(response.Payload))

How do you use a nodejs Lambda in AWS as a producer to send messages to MSK topic without creating EC2 client server?

I am trying to create a Lambda in AWS that serves as a producer to an MSK topic. All the AWS docs say to create a new EC2 instance, but as my Lambda is in the same VPC I feel like this should work. I am very new to this and I notice my log statement never hits in my producer.on function.
I am using nodejs and the kafka-node module. The code can be found below.
Essentially, I am just wondering if anyone knows how to do this and why the producer.on function is never hit when I run test through the Lambda? This is just some test code to see if I can get it to send, but if any more data is needed oy help please let me know and thanks in advance.
exports.handler = async (event, context,callback) => {
const kafka = require('kafka-node');
const bp = require('body-parser');
const kafka_topic = 'MyTopic';
const Producer = kafka.Producer;
var KeyedMessage = kafka.KeyedMessage;
const Client = kafka.Client;
const client = new kafka.KafkaClient({kafkaHost: 'myhost:9094'});
console.log('client :: '+JSON.stringify(client));
const producer = new Producer(client);
console.log('about to hit producer code');
producer.on('ready', function() {
console.log('Hello there!')
let message = 'my message';
let keyedMessage = new KeyedMessage('keyed', 'me keyed message');
producer.send([
{ topic: kafka_topic, partition: 0, messages: [message, keyedMessage], attributes: 0 }
], function (err, result) {
console.log(err || result);
process.exit();
});
});
producer.on('error', function (err) {
console.log('error', err);
});
}
return "success";
What you need is to be able to produce messages on your MSK cluster using REST API. Why not setup a REST proxy for MSK as detailed here and then call this API to produce your messages to MSK.

Unable to query dynamodb GSI in lambda locally

So I added a lambda function category using the amplify CLI, in order to query data from the GSI(Global secondary Index) I created using the #key directive in the graphql schema. Whenever I try mocking the function locally using the amplify mock function <functionName> the callback function of the query keeps on returning null. The function can be seen below
const AWS = require("aws-sdk");
const db = new AWS.DynamoDB.DocumentClient({
region: process.env.REGION,
apiVersion: "2012-08-10",
});
const params = {
// ProjectionExpression: ["province", "gender", "updatedAt", "createdAt"],
ExpressionAttributeValues: {
":provinceVal": "Sichuan",
},
IndexName: "RegistreesByProvince",
KeyConditionExpression: "province = :provinceVal",
TableName: process.env.API_PORTAL_SUBMISSIONSTABLE_NAME,
};
const calculateStatistics = async () => {
try {
const data = await db.query(params).promise();
console.log(data);
} catch (err) {
console.log(err);
}
};
const resolvers = {
Query: {
getStatistics: () => {
return calculateStatistics();
},
},
};
exports.handler = async (event) => {
// TODO implement
const typeHandler = resolvers[event.typeName];
if (typeHandler) {
const resolver = typeHandler[event.fieldName];
if (resolver) {
var result = await resolver(event);
return result;
}
}
}; // };
I then tried to capture the whole event and logged it to the console as can be seen in the calculateStatistics function, which now showed me a bit more explicit error as follows.
{ UnknownEndpoint: Inaccessible host: `dynamodb.us-east-1-fake.amazonaws.com'. This service may not be available in the `us-east-1-fake' region.
at Request.ENOTFOUND_ERROR (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/event_listeners.js:501:46)
at Request.callListeners (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/request.js:688:14)
at ClientRequest.error (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/event_listeners.js:339:22)
at ClientRequest.<anonymous> (/Users/apple/Documents/work/web/portal/amplify/backend/function/calcStatistics/src/node_modules/aws-sdk/lib/http/node.js:96:19)
at ClientRequest.emit (events.js:198:13)
at ClientRequest.EventEmitter.emit (domain.js:448:20)
at TLSSocket.socketErrorListener (_http_client.js:401:9)
at TLSSocket.emit (events.js:198:13)
message:
'Inaccessible host: `dynamodb.us-east-1-fake.amazonaws.com\'. This service may not be available in the `us-east-1-fake\' region.',
code: 'UnknownEndpoint',
region: 'us-east-1-fake',
hostname: 'dynamodb.us-east-1-fake.amazonaws.com',
retryable: true,
originalError:
{ Error: getaddrinfo ENOTFOUND dynamodb.us-east-1-fake.amazonaws.com dynamodb.us-east-1-fake.amazonaws.com:443
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:56:26)
message:
'getaddrinfo ENOTFOUND dynamodb.us-east-1-fake.amazonaws.com dynamodb.us-east-1-fake.amazonaws.com:443',
errno: 'ENOTFOUND',
code: 'NetworkingError',
syscall: 'getaddrinfo',
hostname: 'dynamodb.us-east-1-fake.amazonaws.com',
host: 'dynamodb.us-east-1-fake.amazonaws.com',
port: 443,
region: 'us-east-1-fake',
retryable: true,
time: 2020-08-12T10:18:08.321Z },
time: 2020-08-12T10:18:08.321Z }
Result:
null
Finished execution.
I then did more research and came across this thread about inaccessible-dynamodb-host-when-running-amplify-mock which I followed and tried implementing to but to no avail. Any help on this would be very much appreciated.
PS: It is worth mentioning that I was able to successfully query for this data through the Appsync console, which led me to strongly believe the problem lies in the function itself.
After doing more research and asking around, I finally made sense of the answer that was provided to me on github that
When running mock on a function which has access to a dynamodb
table generated by API. It will populate the env with fake values. If
you would like to mock your lambda function against your deployed
dynamodb table you can edit the values in the sdk client so it can
make the call accurately.
In summary, if you are running things locally, then you wouldn't have access to your backend variables which you might try mocking. I hope this helps someone. Thanks!

How to fetch data from a REST API in serverless?

I am new to serverless. I want to fetch data from google. I am using Google Custom Search engine. Although I got results when I run locally. But when I deploy to AWS Lambda I am getting "Internal Server Error". Can anyone help me to fix the issue?
'use strict';
var request = require('request');
module.exports.get = (event, context, callback) => {
request('https://www.googleapis.com/customsearch/v1?q=Serverless+AWS+Lambda&cx=xxxxxxxxxxx&key=API_key&num=10', function (error, response, body) {
if (!error && response.statusCode == 200) {
callback(null, response);
console.log(body);
} else {
console.warn(error);
}
});
};
I want a json output. I would like to save that result
Internal Server Error mostly points out that your lambda code could not be executed correctly. Did you pack all your dependencies (node_modules) within the ZIP file you provide to AWS lambda (e.g. request ?)

How to fix AWS Device farm SDK error Unexpected key 'type' found in params

I am trying to get the list of uploads in the AWS Device Farm. I tried to use the method "devicefarm.listUploads" from Lambda.
I am facing an issue when I am trying to filter it by type.
var uploadList = devicefarm.listUploads({ arn: deviceFarmProject, type: 'IOS_APP' }).promise()
.then(res => res)
.catch(err => err);
The expectation is to get data about all the iOS apps, but getting the bellow error.
{
"message": "Unexpected key 'type' found in params",
"code": "UnexpectedParameter",
"time": "2019-05-02T15:49:35.351Z"
}
~~I'm not sure why the type isn't recognized here~~
[Edit]
The reason for this error is due to the version of the aws-sdk in AWS Lambda.
https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
Node.js Runtimes
Name Identifier AWS SDK for JavaScript
Node.js 8.10
nodejs8.10
2.290.0
I created a Lambda layer with the following commands and applied it to my function through the web console.
npm init
npm install aws-sdk
mkdir nodejs
cp -r node-modules nodejs
zip -r aws-sdk-layer.zip nodejs
note the zip file structure needs to match the Lambda documentation example.
https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path
Node.js – nodejs/node_modules, nodejs/node8/node_modules (NODE_PATH)
Example AWS X-Ray SDK for Node.js
xray-sdk.zip
└ nodejs/node_modules/aws-xray-sdk
after I applied the layer I was able to execute the function successfully.
but I used the following and it seemed to work though I didn't have any iOS uploads.
// assume we already executed `npm install aws-sdk`
var AWS = require('aws-sdk');
// Device Farm is only available in the us-west-2 region
var devicefarm = new AWS.DeviceFarm({ region: 'us-west-2' });
var params = {};
devicefarm.listProjects(params, function (err, projects) {
if (err) console.log(err, err.stack); // an error occurred
else{
project = projects.projects[0];
console.log("project: ", project);
uploadList = devicefarm.listUploads({ arn: project.arn, type: 'IOS_APP' }).promise()
.then(function(uploadList){
console.log("uploads: ",uploadList);
})
.catch(err => err);
}
});
code I executed in Lambda
// assume we already executed `npm install aws-sdk`
var AWS = require('aws-sdk');
// Device Farm is only available in the us-west-2 region
var devicefarm = new AWS.DeviceFarm({ region: 'us-west-2' });
exports.handler = async (event) => {
return new Promise(function (resolve, reject) {
var params = {};
devicefarm.listProjects(params, function (err, projects) {
if (err) reject(err); // an error occurred
else {
var project = projects.projects[0];
console.log("project: ", project);
resolve(project);
}
});
}).then(function(data){
console.log("in then function","data: ",data);
return new Promise(function(resolve,reject){
devicefarm.listUploads({ arn: data.arn, type: 'IOS_APP' }, function(err,uploads){
if (err) reject(err); // an error occurred
else {
resolve(uploads);
}
})
}).then(function(data){
console.log("uploads: ", data);
return data;
}).catch(function(data){
console.error("list uploads failed","data: ", data);
return data;
});
}).catch(function(data){
console.error("list projects failed","data: ",data);
return data;
});
};
It might be the case that the aws-sdk version in Lambda isn't up to date in which case you would need to apply a Lambda layer or include the aws-sdk in the code package.
Locally I executed this code and it provided the following output:
node sample.js
project: { arn: 'arn:aws:devicefarm:us-west-2:111122223333:project:00ec5d2a-9170-4c52-b65e-0e12986e4fc3',
name: 'web_app_test',
created: 2019-02-10T22:47:35.052Z }
uploads: { uploads: [] }
aws-sdk version: aws-sdk#2.448.0
node --version
v8.12.0
HTH
James

Resources