Kyner
Kyner

Reputation: 41

AWS Lambda - Telegram Bot with MySQL - Loop Message \ Same Message

I am developing an AWS Lambda Function to host my Telegram Bot.

Project Details:

Simple Workflow:

The Code

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

Answers (1)

Kyner
Kyner

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:

  • Lambda: Maximum 15 minutes
  • API Gateway: Maximum - 30 seconds

After understanding these values, I started checking my Lambda Function log:

  • Original Code: 1 minute to finish the execution
  • Improved Code: 40 seconds to finish the execution

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

  • User Sends a Telegram Message -> Telegram Webhook -> API Gateway -> AWS Lambda -> MYSQL Query -> Reply for the Telegram User

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:

  • Lambda 1 -> Invoke Lambda 2
  • Lambda 2 -> Send Status 202 for Lambda 1
  • Lambda 1 -> Send Status 200 for Telegram Webhook
  • Lambda 2 -> Keep Running Until Finish the Job

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:

  • Lambda 1
    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: ''})
    }
  • Lambda 2

    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:

enter image description here

Upvotes: 1

Related Questions