Reputation: 41
I am developing an AWS Lambda Function to host my Telegram Bot.
Project Details:
Simple Workflow:
The Code
Index.js
const bot = require('./Bot')
exports.handler = function(event, context, callback) {
const tmp = JSON.parse(event.body)
bot.handleUpdate(tmp)
.then(() => {
var response = {"statusCode": 200, "body": "OK"}
//callback(null, response)
//context.succeed(response)
})
}
In the Bot.js, there is an MYSQL Query to check if the user is sending a message under the allowed days and hours.
The Issue:
If I use the callback(null, response)
In this scenario, I keep receiving the same message from the webhook in a loop. As far as I could see the response is not working
If I use the context.succeed(response)
In this scenario, I receive the original message just one time.
Anyone knows what could solve this issue. I already tried to use context and callback, but the query is not running, and the user is not receiving the reply.
Upvotes: 3
Views: 642
Reputation: 41
After a long time checking all logs and understand the scenario of my infrastructure, I solved the issue. Let´s first understand the situation in a better way:
More details for the scenario:
I checked what the maximum acceptable values for the timeout in API Gateway and Lambda are:
After understanding these values, I started checking my Lambda Function log:
As you can see, even after improving my code, it was not finishing before the API Gateway timeout. It started the issue I was facing.
If you check your Telegram Webhook Info:
I was getting the same message in Pending Status over and over again. It was causing the loop in the messages received. If you don´t give a response to Telegram Webhook with Status 200, It will keep sending that message for you.
Back to the Simple Workflow
The issue happens between Telegram Webhook and API Gateway. As my Lambda Function takes more than 30 seconds to finish, our API Gateway will never send the response. It makes Telegram Webhook keep sending the same message over and over again.
My Search to Solve it:
We need to send the response back under the API Gateway timeout (30 seconds), but we also need to keep our Lambda function running until it is finished with the expected result.
After searching, I found the topic: Nodejs - Invoke an AWS.Lambda function from within another lambda function
If we invoke a second Lambda, we could run it in parallel while the first Lambda could send the expected response for Telegram Webhook.
The Solution:
Based on this topic I checked a little bit how I could run a second Lambda Function without waiting for a response, and the answer was: "Lambda as an EVENT"
More details here: https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html
As this topic explains if you Invoke a Lambda Function as an EVENT what will happen:
This solved the whole issue.
Now Telegram Webhook is receiving the expected status, and my Bot is running in parallel. Now maybe you are expecting the final code. So I will share it with you.
Code:
AWS = require('aws-sdk');
AWS.config.region = 'sa-east-1'; //Change for your own region
var lambda = new AWS.Lambda();
exports.handler = function(event, context, callback) {
console.log(event)
var params = {
FunctionName: 'Lambda Function Name',
InvocationType: 'Event',
Payload: JSON.stringify(event)
};
lambda.invoke(params, function(err, data) {
if (err) {
console.log(err)
}
})
callback(null, {statusCode: 200, body: ''})
}
const bot = require('./Bot')
exports.handler = function(event) {
const tmp = JSON.parse(event.body)
bot.handleUpdate(tmp)
}
Additional Tip:
Your Lambda 1 will need the necessary roles to run the Lambda 2. If you enable the CloudWatch Logs it will provide you all necessary role, but I will share the role I set below:
Upvotes: 1