Error from cloudfront in serverless framework lambda function - aws-lambda

I am trying to deploy a simple Slack lambda api which uses the #slack/client library to remove members and pinned messages from a specific channel. The issue that I am running into is the function executes without a problem, and it is removing the channel members without a problem, but my Lambda function keeps returning:
HTTP/1.1 502 Bad Gateway
...
X-Cache: Error from cloudfront
...
{
"message": "Internal server error"
}
as the response body. When I check the logs using sls logs -f api, I dont see any errors there either. I see the console.log of my function successfully executing.
My serverless.yml is as follows:
provider:
name: aws
runtime: nodejs10.x
profile: serverless
functions:
api:
handler: handler.api
timeout: 30
events:
- http:
method: POST
path: clean
And my api code, i have removed the unnecessary function codes as they are doing their work, is :
module.exports.api = async (event, context, callback) => {
let channel = JSON.parse(event.body).ctf
let id = await findChannelId(channel)
removeMembersFromChannel(id[0]).then(() => {
removePinsFromChannel(id[0]).then(() => {
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: `Cleaned ${channel} ${id}`,
}, null, 2),
})
})
})
};
Things I have tried:
returning the response instead of using the callback
using promises and async await
testing the function locally using sls invoke local
most of my search shows that this could be a permission issue, but all the references are for s3 usage which is something i am not using.
Questions
Why am I getting this error, and how I can resolve this?
After referenceing this In the handler function, I am using JSON.stringify. Using the serverless-framework, how can i avoid using Lambda proxy integration?

Please, add console.log for detailed logging via cloudwatch and use x-ray. Some typical problems with cloudfront:
- a lot of time to propagate to edge locations (maybe u need recreate your cdn)
- logs from lambda#edge locates in invoked region

Related

How To Solve 504 Bad Gateway Timeout Error From Aws Api Gateway?

I am getting 504 Bad Gateway Timeout error in responce but data gets inserted sucessfully to the databse.
Code executes perfectly locally with response time within 1.15s but whenever deployed to lambda it start giving this Timeout Error.
Node js Endpoint Route is as Follows
route.post("/Register", async (req, res) => {
try {
const user = new userschema({
Name: req.body.Name,
Email: req.body.Email,
UserName: req.body.UserName,
PhotoUrl: req.body.PhotoUrl,
});
await user.save();
return res.status.send("Created");
} catch (error) {
return res.status(500).send("Something Went Wrong");
}
});
I have Deployed Nodejs backend to aws lambda which is running in a VPC and using mongodb atlas it follow this architecture
I am new to aws so i followed This Youtube Video.
Data gets inserted to mongodb atlas Database sucessfully. So the Vpc Peering conncetion beetween lambda function and Mongodb Atlas must be all right.
Cloudwatch Logs is as Follows
I tried everything i could but still facing this issue.

Serverless handler for Apollo Server throws error that it cant identify events on Netlify

Context:
I am trying to deploy GraphQL using Apollo Server Lambda through Netlify. My handler is as below:
Code:
exports.handler = server.createHandler({
cors: {
origin: '*'
}
});
I was able to build and deploy successfully on Netlify - however the server threw an error at launch. Netlify is looking for an event to trigger but the Apollo Server handler I have used does not provide. How do we connect this handler to a handler that uses events?
Error Message:
{"errorType":"Error","errorMessage":"Unable to determine event source based on event.","trace":["Error: Unable to determine event source based on event."," at getEventSourceNameBasedOnEvent (/var/task/node_modules/#vendia/serverless-express/src/event-sources/utils.js:88:9)"," at proxy (/var/task/node_modules/#vendia/serverless-express/src/configure.js:38:51)"," at handler (/var/task/node_modules/#vendia/serverless-express/src/configure.js:99:12)"," at Runtime.handler (/var/task/node_modules/apollo-server-lambda/dist/ApolloServer.js:51:27)"]}
It looks like the request doesn't contain some AWS lambda specific event params when using Netlify CLI while #vendia/serverless-express expects them. I was able to fix a similar case in local dev environment with this:
const serverHandler = server.createHandler({
cors: {
origin: '*'
}
});
exports.handler = (event, context, callback) => {
return serverHandler(
{
...event,
requestContext: event.requestContext || {},
},
context,
callback
);
}

Websocket request succeeds in writing to DynamoDB but returns Internal Server Error

I created an AWS API Gateway route for Websocket connections. I started with the AWS provided Simple Web Chat templates but have modified it to fit my needs. The API Gateway calls a Lambda function that writes to a DynamoDB table.
I am able to make a websocket connection but when I make my next request to insert some data the data appears successfully in my DynamoDB table but the response I get back is Internal Server Error.
I don't understand what is causing the Internal Server Error. When I look in the CloudWatch logs I just see normal traffic with no errors.
I could use some help understanding what is going wrong or how I can troubleshoot this better.
Here is the Lamba function that is being called:
const AWS = require("aws-sdk");
const customId = require("custom-id");
const ddb = new AWS.DynamoDB.DocumentClient({
apiVersion: "2012-08-10",
region: process.env.AWS_REGION,
});
exports.handler = async (event) => {
const uniqueId = customId({
randomLength: 1,
});
const data = {
uniqueId: uniqueId,
members: [
{
connectionId: event.requestContext.connectionId,
},
],
events: [],
parameters: [],
};
const putParams = {
TableName: process.env.EVENT_TABLE_NAME,
Item: data,
};
try {
await ddb.put(putParams).promise();
} catch (err) {
return {
statusCode: 400,
body: "Failed to create: " + JSON.stringify(err),
};
}
return { statusCode: 200, body: putParams };
};
Image of AWS CloudWatch Logs
The error returned by wcat looks like this:
{"message": "Internal server error", "connectionId":"NZxV_ddNIAMCJrw=", "requestId":"NZxafGiyoAMFoAA="}
I just had the same problem. The issue in my case was because API Gateway did not have permission to call the Lambda function in order to process a message arriving from the websocket. The 'internal server error' in this case is API Gateway saying it had some problem when it tried to invoke the Lambda function to handle the websocket message.
I was using CDK to deploy the infrastructure, and I created one WebSocketLambdaIntegration for the connect, disconnect and default websocket handlers, but this doesn't work. You have to create separate WebSocketLambdaIntegration instances even if you are calling the same Lambda function for all websocket events, otherwise CDK does not set the correct permissions.
I could see this was the problem because 1) I was using the same Lambda function for the connect, disconnect and default routes, and 2) in CloudWatch Logs I was only seeing log messages for one of these routes, in this case the 'connect' one. When I sent a message over the websocket, I was not seeing the expected log messages from the Lambda that was supposed to be handling incoming websocket messages. When I disconnected from the websocket, I did not see the expected log messages from the 'disconnect' handler.
This was because CDK had only given Lambda invoke permission to specific routes on the API Gateway websocket stage, and it had only authorised the 'connect' route, not the others.
Fixing the CDK stack so that it correctly assigned permissions, allowing API Gateway to invoke my Lambda for all websocket routes, fixed the problem.
I see it now. It was the last line. I changed it and now it works fine.
return { statusCode: 200, body: JSON.stringify(putParams) };

Can't get oauth token from google smart home action sync intent in aws lambda

I am using aws lambda function for google smart home action. I used aws api gateway for fulfillment url to reach lambda. I can successfully handle google assistant's intents with below code:-
const {smarthome} = require('actions-on-google');
const app = smarthome();
app.onExecute((body, headers) => {
return {
requestId: 'ff36...',
payload: {
// ...
},
};
});
app.onQuery((body, headers) => {
return {
requestId: 'ff36...',
payload: {
// ...
},
};
});
app.onSync((body, headers) => {
console.log("body: "+JSON.stringify(body));
console.log("headers: "+JSON.stringify(headers));
return {
requestId: 'ff36...',
payload: {
// ...
},
};
});
exports.handler = app;
On hard coding device details in this function, It can successfully reflect in google home app. But to get actual devices of user I need to get oauth token from "SYNC" intent. But all I got from this code is this output:-
body: {"inputs":[{"intent":"action.devices.SYNC"}],"requestId":"5604033533610827657"}
headers: {}
Unlike "Discover Directive" of Alexa's skill, which contains token in request.directive.endpoint.scope.token, google's intent doesn't seems to carry it. For O Auth, I am using AWS Cognito which works fine with Alexa Account linking and for google home too it can successfully link the account and show devices which I hardcode in lambda function.
As per this answer, the token is in
headers.authorization.substr(7)
I've tried that and got nothing. It shows
"Cannot read property 'substr' of undefined".
The lambda handler in the Actions on Google client library assumes that the request headers are present at event.headers within the input event parameter of a Lambda Proxy Integration. If you have a custom Lambda integration or have otherwise modified the input mapping, you may need to edit your mapping template to ensure the headers are placed where the client library expects.

botframework hosted in AWS API Gateway

I have been trying to deploy my botframework bot in to AWS API Gateway. I am using the aws serverless express framework to host this application.
The only thing I can find is this conversation which gives some good ideas on how to get this working.
https://gitter.im/Microsoft/BotBuilder?at=57832060bdafd191075d92b3
The suggestion from the above was to pass to the request to listener function which work well
{ body:{}, headers: {} }
and use the following for the response where end can be a no-op.
{ status: function (code) {}, end: () {} }
My code that runs but doesn't receive a response from the bot is this.
var connectorListener = connector.listen();
function listen() {
return function (req, res) {
var response = res;
connectorListener(req, { status: (code) => { response.status(code); }, end: () => { response.end(););
}
}
If I remove res.end() and leave as a no op as suggested I get a response back from the chatbot in 1-2 seconds, but it also makes the lambda run for 30 seconds which is the timeout for API Gateway.
Is there a way to make this work so I can receive messages back without making the lambda timeout?

Resources