I'm using cities stored in a DynamoDB table to make calls to an external weather API to determine whether it will rain in that city on that day. It then calls a separate Lambda that uses that info to message subscribers of an SNS topic that it will rain.
const AWS = require('aws-sdk');
AWS.config.update({ region: 'eu-west-2' });
const lambda = new AWS.Lambda();
const axios = require('axios');
const tableName = process.env.CITY_TABLE;
const docClient = new AWS.DynamoDB.DocumentClient();
const publishMessageLambda = process.env.PUBLISH_MESSAGE_LAMBDA_NAME;
const weatherApiKey = process.env.WEATHER_API_KEY;
exports.handler = async (event) => {
const scanParams = {
TableName: tableName,
AttributesToGet: ['city'],
};
try {
let citiesArr = await docClient.scan(scanParams).promise();
citiesArr.Items.forEach(async (cityObj) => {
// console.log('cityObj', cityObj);
// console.log('city', cityObj.city);
// console.log('weatherApiKey:', weatherApiKey);
let weatherReport = await axios({
method: 'get',
url: 'http://api.weatherapi.com/v1/forecast.json',
params: {
key: weatherApiKey,
q: cityObj.city,
days: 1,
},
});
// console.log(weatherReport);
let city = cityObj.city;
let dailyChanceOfRain = Number(
weatherReport.data.forecast.forecastday[0].day.daily_chance_of_rain
);
let totalPrecip =
weatherReport.data.forecast.forecastday[0].day.totalprecip_mm;
let lambdaParams = {
FunctionName: publishMessageLambda,
InvocationType: 'RequestResponse',
Payload: JSON.stringify({
body: { dailyChanceOfRain, totalPrecip, city },
}),
};
console.log('dailyChanceOfRain: ', dailyChanceOfRain);
console.log('totalPrecip: ', totalPrecip);
if (dailyChanceOfRain > 50 && totalPrecip > 3) {
let data = await lambda.invoke(lambdaParams).promise();
}
// console.log(
// 'weatherReport: ',
// weatherReport.data.forecast.forecastday[0].day
// );
});
} catch (error) {
console.log(error);
}
};
Running the function locally produces the desired logs on the command line however when running the function on Lambda the logs involving the external http request don't show on the cold start and the logs only show up once the function has been invoked multiple times and often not together.
Any advice would be much appreciated.
Related
My Lambda function does not call the S3 upload function where it is supposed to send a URL back that will be assigned to the DynamoDB database. I can't seem to pin-point what's wrong here. I have tried to just call the Lambda upload to S3 function without the rest of the code and it work's fine.
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const BUCKET_NAME = 'BUCKET_NAME';
const dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
let body;
let statusCode = 200;
const uploadFileToS3 = async (fileBinary) => {
try {
const base64File = fileBinary;
const decodedFile = Buffer.from(
base64File.replace(/^data:image\/\w+;base64,/, ''),
'base64'
);
const params = {
Bucket: BUCKET_NAME,
Key: `images/${new Date().toISOString()}.jpeg`,
Body: decodedFile,
ContentType: 'image/jpeg',
};
const uploadResult = await s3.upload(params).promise();
console.log(uploadResult)
return uploadResult;
} catch (e) {
console.error(e);
}
};
try {
switch (event.routeKey) {
case 'PUT /items':
let requestJSON = JSON.parse(event.body);
const fileURL = await uploadFileToS3(requestJSON.itemPicture);
await dynamo
.put({
TableName: 'TABLE_NAME',
Item: {
itemId: requestJSON.itemId,
userId: requestJSON.userId,
itemTitle: requestJSON.itemTitle,
itemDesc: requestJSON.itemDesc,
itemLocation: requestJSON.itemLocation,
itemPrice: requestJSON.itemPrice,
itemPicture: fileURL,
},
})
.promise();
body = `Put item ${requestJSON.itemId}`;
break;
default:
throw new Error(`Unsupported route: ` + `${event.routeKey}`);
}
} catch (err) {
statusCode = 400;
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
I am using a lambda function for dynamo streaming after a record is inserted.
However, after the dynamoDB.update call, it seems the lambda is dead, and there are no other logs printed. Can anyone help?
Here is my javascript code:
/* Amplify Params - DO NOT EDIT
API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_ARN
API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME
ENV
REGION
Amplify Params - DO NOT EDIT */
const AWS = require('aws-sdk');
const awsConfig = {
region: process.env.REGION,
endpoint:
process.env.DYNAMODB_ENDPOINT ||
`https://dynamodb.${process.env.REGION}.amazonaws.com`
};
const dynamoDB = new AWS.DynamoDB.DocumentClient(awsConfig);
async function handleNewEmployeeInfo(dynamoId, employeeId) {
console.log(
`[handleNewEmployeeInfo] begin. dynamoId(${dynamoId}) employeeId(${employeeId})`
);
try {
const employeeName = "TestString";
// this log is working
console.log(
'try to update table:',
process.env.API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME,
dynamoId,
employeeName
);
// something wrong with the update
await dynamoDB
.update({
TableName: process.env.API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME,
Key: {
id: dynamoId
},
UpdateExpression: `set employeeName = :employeeName`,
ExpressionAttributeValues: {
':employeeName': employeeName
}
})
.promise()
.then((data) => console.log(data.Attributes))
.catch(console.error);
} catch (error) {
// NOT working
console.log('[ERROR]:', error);
}
// NOT working
console.log('[FINISH] call end');
}
async function handleEventRecord(record) {
console.log(record.eventID);
console.log(record.eventName);
try {
// after EmployeeInfo is created by the admin
if (record.eventName === 'INSERT') {
const arn = record.eventSourceARN;
console.log(`[INSERT][${arn}]: ${JSON.stringify(record)}`);
if (arn.includes(':table/EmployeeInfo')) {
const dynamoId = record.dynamodb.NewImage.id['S'];
const employeeId = record.dynamodb.NewImage.employeeId['S'];
await handleNewEmployeeInfo(dynamoId, employeeId);
}
}
} catch (error) {
console.log('[ERROR]:', error);
}
}
/**
* #type {import('#types/aws-lambda').APIGatewayProxyHandler}
*/
exports.handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
event.Records.forEach(async (record) => {
await handleEventRecord(record);
});
return Promise.resolve('Successfully processed DynamoDB record');
};
After I remove the update logic, the following log works fine. So I am pretty sure it is the update line has the problem.
I am trying to call AWS AppSync service from AWS Lambda function using IAM permissions. Just a basic mutation or query call. I found this tutorial:
https://aws.amazon.com/blogs/mobile/supporting-backend-and-internal-processes-with-aws-appsync-multiple-authorization-types/
but it no longer works with the latest sdks. Errors out on lines 3, 4, etc.
require('isomorphic-fetch');
const AWS = require('aws-sdk/global');
const AUTH_TYPE = require('aws-appsync').AUTH_TYPE;
const AWSAppSyncClient = require('aws-appsync').default;
const gql = require('graphql-tag');
const config = {
url: process.env.APPSYNC_ENDPOINT,
region: process.env.AWS_REGION,
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: AWS.config.credentials,
},
disableOffline: true
};
const createLogMutation =
`mutation createLog($input: CreateLogInput!) {
createLog(input: $input) {
id
event
detail
}
}`;
const client = new AWSAppSyncClient(config);
exports.handler = (event, context, callback) => {
// An expected payload has the following format:
// {
// "event": "sample event",
// "detail": "sample detail"
// }
const payload = event['Records'][0]["Sns"]['Message'];
if (!payload['event']) {
callback(Error("event must be provided in the message body"));
return;
}
const logDetails = {
event: payload['event'],
detail: payload['detail']
};
(async () => {
try {
const result = await client.mutate({
mutation: gql(createLogMutation),
variables: {input: logDetails}
});
console.log(result.data);
callback(null, result.data);
} catch (e) {
console.warn('Error sending mutation: ', e);
callback(Error(e));
}
})();
};
Can someone please post a basic code for calling query/mutation from lambda using IAM permissions?
I am using aws lambda that gets a list of items and it pushes items in the table asynchronously. Here promise.all(promiseList) does not add the data in the table but doing promise.all(promiseList[0]) ensures that my first element is pushed in the table. How can I make it to wait for all?
My code-
let promiseList = [];
// await Promise.all(
promiseList.push(
event.Records.map(async record => {
console.log(record.dynamodb.Keys.ServiceOrderId.S);
console.log('Inside initiate payment');
const paymentObject = {
paymentId: record.dynamodb.Keys.ServiceOrderId.S,
totalAmount: "1200"
};
console.log(paymentObject);
const dynamoDBParams = {
TableName : TABLE_NAME,
Item : paymentObject
};
return await DynamoDBClient.put(dynamoDBParams).promise();
}
)
);
return await Promise.all(promiseList[0]);
couple of changes I can see
We don't need to await for every put to complete, it will be inefficient, we want continue executing all at once.
DynamoDBClient.put(dynamoDBParams).promise() is returning a promise, which can be pushed into an array, rather than pushing entire loop
Here is how full Lambda looks like:
const AWS = require("aws-sdk");
AWS.config.update({ region: "us-east-1" });
let docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async function(event) {
const table = 'test'
var promiseArray = [];
event.Records.map(record => {
console.log('record', record);
const promise = docClient.put({
TableName: table,
Item: {
pk: record.pk,
title: record.title,
},
}).promise();
promiseArray.push(promise)
})
return Promise.all(promiseArray);
}
[EDIT]
I am new to AWS and I've been trying to make a real-time chat application. I saw this code, so I might as well try this. I tried to follow everything but it seems there is a problem.
[END]
I got an error with this code stating, Cannot read "domainName" of undefined which got me confused. Is this because of my API Gateway? I already connected this to another route named "Message" and I already have the integration request of my connect and disconnect.
Below is my code:
const AWS = require('aws-sdk');
const db = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
require('./index.js');
let send = undefined;
function init(event) {
console.log(event);
const apigwManagementApi = new AWS.ApiGatewayManagementApi({
apiVersion: '2018-11-29',
endpoint: event.requestContext.domainName + '/' + event.requestContext.stage
});
send = async (connectionId, data) => {
await apigwManagementApi.postToConnection({
ConnectionId: connectionId,
Data: `Echo: ${data}` }).promise();
}}
exports.handler = (event, context, callback) => {
init(event);
let message = JSON.parse(event.body).message;
getConnections().then((data) => {
console.log(data.Items);
callback(null, {
statusCode: 200,
});
data.Items.forEach(function(connection) {
console.log("Connection " +connection.connection_id);
send(connection.connection_id, message);
});
});
return {};
};
function getConnections(){
const params = {
TableName: 'GroupChat',
}
return db.scan(params).promise();
}