0

I created a telegram bot using python-telegram-bot v 20.2. I run it on the computer using application.run_polling(), and everything works fine.

But when I try to place it on a serverless structure with an entry point (handler(event, context)), I don't understand how to make it work.

I added a webhook without any problems using setWebhook. And I get the data without any problems using json.loads(event\['body'\]).

I tried using the solution from here, but couldn't figure out how it works.

Please tell me how to make the serverless function respond to me in telegram.

Code:

# A simple example of a handler that I found.
async def handler(event, context):
    body = json.loads(event['body'])
    print(body)
    return {
        'statusCode': 200,
        'body': 'Webhook request received'
    }
# The code that works on my computer.
def main() -> None:
    application = Application.builder().token(config.MYTOKEN).build()
    application.add_handler(CommandHandler("start", send_welcome))
    application.run_polling()

if __name__ == '__main__':
    main()
Mouz
  • 13
  • 3

3 Answers3

0

You were already on the right wiki page ;) Please read the last paragraph "Alternative: No long running tasks".

The point is that run_polling (as wrapper around Application.{initialize, start, stop, shutdown}) is designed for scripts that run 24/7, which is not what you need in your case. You only need to call Application.initialize, Application.process_update and Application.shutdown.


Disclaimer: I'm currently the maintainer of python-telegram-bot.

CallMeStag
  • 5,467
  • 1
  • 7
  • 22
0

Thanks to CallMeStag for the answer.

The final code looks like this:

async def handler(event, context):
    application = Application.builder().token(config.MYTOKEN).build()
    application.add_handler(CommandHandler("start", send_welcome))
    body = Update.de_json(data=json.loads(event['body']), bot=application.bot)
    await application.initialize()
    await application.process_update(body)
    await application.shutdown()
    return {
         'statusCode': 200,
         'body': 'Webhook request received'
    }
Mouz
  • 13
  • 3
0

Hello I also struggled with this issue of transitioning from application.run_polling() to webhooks using a handler so it can be run on cloudrun. I reference one of the examples from the PTB docs here: However not that this was with PTB V13 so I had to make some updates to support the new async/await structure.

This is code for simple echo using async await running on cloudrun

app = Flask(__name__)

application = ApplicationBuilder().token(os.environ["TOKEN"]).build()

async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    await update.message.reply_text(update.message.text)

echo_handler = MessageHandler(filters.TEXT & (~filters.COMMAND), echo)
application.add_handler(echo_handler)

@app.route('/', methods=['POST'])
async def webhook():
    if request.headers.get('content-type') == 'application/json':
        async with application:
            update = Update.de_json(request.get_json(force=True),application.bot)
            await application.process_update(update)
            return ('', 204)
    else:
        return ('Bad request', 400)

Using asyncio you could simplify the code in your handler using

async with application:
            update = Update.de_json(request.get_json(force=True),application.bot)
            await application.process_update(update)

This is from the PTB docs, it removes the need to call initalize(),process_update() then shutdown(). Your application can also then be built outside of the hook instead of in the handler.

Joseph
  • 1
  • 1