I have a lambda function that verifies user credentials. Upon success it should call another lambda function, as a destination, that generates a token. When I test the first function, it is successful but it does not call the destination which is the other lambda function. It only gives me the success message from the first function.
Function one
exports.handler = function (event, context) {
var id = event.email;
var params = {
TableName: "User",
KeyConditionExpression: "#email = :email",
ExpressionAttributeNames:{
"#email": "email",
},
ExpressionAttributeValues: {
":email": {S: event.email},
}
};
if (id && id !== '') {
dynamo.query(params, function (err, data, callback) {
if (err) {
context.done(err);
}
else {
var user = data.Items[0];
if (user) {
var encryptedParams = {
CiphertextBlob: Buffer.from(user.password.B),
};
kms.decrypt(encryptedParams, function (err, decrypteddata) {
if (err) {
console.log(err, err.stack);
context.done(err);
}
else {
if(event.password == decrypteddata.Plaintext.toString()) {
console.log("User authenticated");
}
}
});
}
}
});
}
else {
return {
statusCode: 400,
body: "No email provided."
}
}
};
Function two
exports.handler = async (event) => {
var expires = moment().add('days', 7).valueOf();
var token = jwt.encode({
iss: event.email,
exp: expires
}, app.get('jwtTokenSecret'));
const response = {
token: token,
express: expires,
statusCode: 200
};
console.log("token granted");
return response;
};
Your code doesn't seem to be indicating when a successful execution has been completed. Destinations needs the "OnSuccess" indicator to determine which destination to trigger. This is possibly why the second function is not being executed.
See: Lambda Destinations: What We Learned the Hard Way - CloudProse - Trek10 Blog
Related
I am trying to have lambda trigger a codebuild function when it hits the point within the lambda function, here is the current code im using for lamda:
console.log('Loading function');
const aws = require('aws-sdk');
const s3 = new aws.S3();
exports.handler = async (event, context) => {
const codebuild = new aws.CodeBuild();
let body = JSON.parse(event.body);
let key = body.model;
var getParams = {
Bucket: 'bucketname', // your bucket name,
Key: key + '/config/training_parameters.json' // path to the object you're looking for
}
if (key) {
const objects = await s3.listObjects({
Bucket: 'bucketname',
Prefix: key + "/data"
}).promise();
console.log(objects)
if (objects.Contents.length == 3) {
console.log("Pushing")
await s3.getObject(getParams, function(err, data) {
if (err)
console.log(err);
if (data) {
let objectData = JSON.parse(data.Body.toString('utf-8'));
const build = {
projectName: "projname",
environmentVariablesOverride: [
{
name: 'MODEL_NAME',
value: objectData.title,
type: 'PLAINTEXT',
},
]
};
console.log(objectData.title)
codebuild.startBuild(build,function(err, data){
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
console.log("Done with codebuild")
}
}).promise();
const message = {
'message': 'Execution started successfully!',
}
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': JSON.stringify(message)
};
}
}
};
Specifically this part should trigger it:
codebuild.startBuild(build,function(err, data){
if (err) {
console.log(err, err.stack);
}
else {
console.log(data);
}
});
But its not, it even outputs after the function? Im thinking its something to do with promises/await/async but cant find the right solution? Any help would be appreciated.
As you pointed out the problem is related to promises. Change your code like this:
const result = await codebuild.startBuild(build).promise();
And if you configured your lambda permissions for CodeBuild it should work.
You can change your s3.getObject the same way without the callback function:
const file = await s3.getObject(getParams).promise();
console.log(file.Body);
I am currently working on an authentication pipeline that has a similar process to OAuth.
If authentication is successful in the third-party authentication system, the value will be transferred to Success Direct url, which I want to communicate with my server to configure to proceed with self-authentication.
In this situation, I organized the api of the success redirect url into lambda and used Lambda's callback object to process responses and requests in a chain.
But the code below always returned the null value, and I have no idea why.
// index.js
const Auth = require('AuthRequest')
exports.handler = async function (event, context, callback) {
if (event.routeKey == 'POST /authentication/success') {
var body = Auth.parse_query_to_json(Auth.decode_base64(event.body));
if (body.resultCode == '0000') { // success
await Auth.get_auth_info(body, callback);
}
else { // failure
callback(null, {
statusCode: 200,
body: 'failure1'
});
}
}
else if (event.routeKey == 'POST /authentication/failure') {
callback(null, {
statusCode: 200,
body: 'failure2'
});
}
};
// authRequest.js
const superagent = require('superagent')
var get_auth_info = async function (body, callback) {
await superagent
.post(url)
.send({
...
})
.set('Content-Type', 'application/json;charset=utf-8')
.end(async function(err, res) {
if(err) {
callback({
statusCode: 200,
body: 'failure3'
});
}
else {
callback(null, res)
}
});
};
var create_user_auth = async function (req, callback) {
await superagent
.post('my-auth-api-uri')
.send({
})
.set('Content-Type', 'application/json;charset=utf-8')
.end(async function(err, res) {
if(err) {
callback({
statusCode: 200,
body: 'failure4'
});
}
else {
if(res.status == 200) {
callback(null, res)
}
else {
callback({
statusCode: 200,
body: 'failure5'
});
}
}
});
};
......
And this lambda funciton is triggered by a API Gateway and uses the event object of Payload 2.0 version using http api.
Is there anyone who knows the answer to this question?
If you want sync handler, then you should not using async function. Docs explain that it should be:
exports.handler = function(event, context, callback) {
Thanks to #Marcin, my code worked perfectly!
// index.js
const Auth = require('AuthRequest')
exports.handler = function (event, context, callback) {
if (event.routeKey == 'POST /authentication/success') {
var body = Auth.parse_query_to_json(Auth.decode_base64(event.body));
if (body.resultCode == '0000') { // success
Auth.get_auth_info(body, callback);
}
else { // failure
callback(null, {
statusCode: 200,
body: 'failure1'
});
}
}
else if (event.routeKey == 'POST /authentication/failure') {
callback(null, {
statusCode: 200,
body: 'failure2'
});
}
};
// authRequest.js
const superagent = require('superagent')
var get_auth_info = function (body, callback) {
superagent
.post(url)
.send({
...
})
.set('Content-Type', 'application/json;charset=utf-8')
.end(function(err, res) {
if(err) {
callback({
statusCode: 200,
body: 'failure3'
});
}
else {
callback(null, res)
}
});
};
var create_user_auth = function (req, callback) {
superagent
.post('my-auth-api-uri')
.send({
})
.set('Content-Type', 'application/json;charset=utf-8')
.end(function(err, res) {
if(err) {
callback({
statusCode: 200,
body: 'failure4'
});
}
else {
if(res.status == 200) {
callback(null, res)
}
else {
callback({
statusCode: 200,
body: 'failure5'
});
}
}
});
};
......
I am trying to pull and display data from DynamoDb by using AWS Lambda function and have it display on AWS Lex. It is returning the if portion with the word "undefined" in the place where the data should be. The information is in the DynamoDB database. I am mainly using AWS servers and building this serverless Lex bot application.
AWS code Segments
const AWS = require('aws-sdk');
const db = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
function getExamSchedule(exam2, table){
return new Promise(function(resolve){
var info = 0;
var params = {
TableName: table,
FilterExpression: "#key = :data",
ExpressionAttributeNames: {
"#key": "Resource",
},
ExpressionAttributeValues:{
":data": exam2
}
};
db.scan(params, function(err, data){
if(err){
console.log("Error: " + err);
info = 0;
} else {
console.log("Success", data);
info = {"ClassID" :data.Items[0].ClassID, "ExamDate " :data.Items[0].ExamDate,
"ExamEndTime:" :data.Items[0].ExamEndTime, "ExamLocation" :data.Items[0].ExamLocation,
"ExamStartTime" :data.Items[0].ExamStartTime};
}
resolve(info);
});
});
}
This is the portion where the issue might be occurring.
exports.handler = async (event, context, callback) => {
var exam2 = event.currentIntent.slots.ClassID;
var info = await getExamSchedule(exam2, "Final_Exams");
var res;
// if (info !== 0)
if(info != null){
res =`The exam information for ${exam2} is ${info.ClassID} Date: ${info.ExamDate}
End time: ${info.ExamEndTime} Location: ${info.ExamLocation} Start time: ${info.ExamStartTime}`;
} else {
res = `The exam is not entered into our database, please look for another exam.`;
}
callback(null, {
"dialogAction": {
"type":"Close",
"fulfillmentState": "Fulfilled",
"message":{
"contentType": "PlainText",
"content": res
}
}
});
};
Could you perhaps share some of the logs and/or stack traces that you encounter when running the code?
I want to send emails using the ses from aws from lambda. The problem is that the email is only sent some times using the same code. We don't get errors.
Here's the code:
const AWS = require('aws-sdk');
var ses = new AWS.SES();
exports.handler = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
await new Promise((resolve, reject) => {
var params = {
Destination: {
ToAddresses: [myEmail]
},
Message: {
Body: {
Text: { Data: "Test"
}
},
Subject: { Data: "Test Email"
}
},
Source: "sourceMail"
};
ses.sendEmail(params, function (err, data) {
if (err) {
console.log(err);
context.fail(err);
} else {
console.log(data);
context.succeed(event);
}
callback(null, {err: err, data: data});
});
});
}
I would be careful with using callbackWaitsForEmptyEventLoop as it can lead to unexpected results (If this is false, any outstanding events continue to run during the next invocation.).
Can you try using this simplified version:
const AWS = require('aws-sdk');
var ses = new AWS.SES();
exports.handler = async (event, context, callback) => {
const params = {
Destination: {
ToAddresses: [myEmail],
},
Message: {
Body: {
Text: { Data: 'Test' },
},
Subject: { Data: 'Test Email' },
},
Source: 'sourceMail',
};
await ses.sendEmail(params).promise();
return event;
};
I am trying to get all the execution history using lambda function and store it to DynamoDB. The function returns about 20 executions and a string value called NextToken that is to be used in the next call to get the rest of the executions.
This is my code.
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient({
region: 'myregion'
});
exports.handler = (event, context, callback) => {
const table = 'myDynamoDB';
const executionARN = "arn:aws:region:accountid:execution:myStateMachine:test";
var stepfunctions = new AWS.StepFunctions();
var params = {
executionArn: executionARN,
maxResults: 20,
nextToken: null,
reverseOrder: false
};
stepfunctions.getExecutionHistory(params, function(err, dataExecution) {
if (err){
console.log(err, err.stack);
}
else {
const params2 = {
TableName: table,
Item: {
id: executionARN,
execution_history: dataExecution
}
};
dynamoDb.put(params2).promise();
}
});
};
nextToken needs to be used in parms pass to next call to getExecutionHistory. You can recursively call this function till all tokens are exhausted. Came across similar situation while fetching logs via Cloud watch.
Sample for fetching history recursively,
Wrap getExecutionHistory into promise and add to different JS file (let's say writer.js) then your main index.js file can call that function like this,
// writer.js which writes record to Dynamodb
// returns promise
// when history is fetched , dynamodb will be inserted and it will resolve dataexecution which has nextToken
module.exports.get = function(fwdtoken) {
if (fwdtoken) parms.nextToken= fwdtoken;
return new Promise ( (resolve, reject)=>{
stepfunctions.getExecutionHistory(params, function(err, dataExecution) {
if (err){
reject(err.stack)
}
else {
const params2 = {
TableName: table,
Item: {
id: executionARN,
execution_history: dataExecution
}
};
dynamoDb.put(params2).promise();
resolve(dataExecution)
}
});
})
};
//This goes in main logic
// Invokes getAllLogs recursilvely
var writer = require('./writer');
var fwdtoken;
function getAllLogs(fwdtoken, fetchCount) {
fetchCount = fetchCount || 0;
if (fetchCount > 40) {
throw new Error("Fetched too many times.");
}
return new Promise( (resolve) => {
writer.get(fwdtoken).then( function consolidate( dataExecution ) {
resolve( dataExecution );
});
})
.then(function ( dataExecution ) {
if (dataExecution.nextForwardToken) {
fwdtoken = dataExecution.nextForwardToken;
getAllLogs(fwdtoken, fetchCount+ 1)
}
else
return fwdtoken
});
}
getAllLogs(fwdtoken, 0);