Skip to content

Bot webhook not waiting for session middleware to finish #5

Description

@elC0mpa

I am migrating a long polling bot to webhook using AWS Lambda. I added '@telegraf/session/mongodb' package to store sesion info in my mongodb database.
After I finished setting up my bot everything works fine but the wizard scenes. I started debuguing and it looks like the problem is related to the session middleware. Let me show you my AWS Cloudwatch logs:

2023-12-20T14:25:29.214Z telegraf:session (642696426) did not find cached session
2023-12-20T14:25:29.214Z telegraf:session (642696426) fetching from upstream store
END RequestId: 5b8e1b5d-4e74-4691-83ac-d21894357d13

As you can see it doesn't print the following message:

2023-12-20T14:25:39.277Z telegraf:session (642696426) updating cache

That's why my code never gets into the wizard scenes. Let me show you my code because maybe I am missing something

export const message = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
  try {
    const body = JSON.parse(event.body!)
    console.log(body)
    initBot()
    await webhookHandle(body)

    return { body: JSON.stringify({ message: 'Ok' }), statusCode: 200 }
  } catch (error) {
    return { body: JSON.stringify({ message: 'Error' }), statusCode: 500 }
  }
}

webhookHandle function:

const webhookHandle = (update: Update) => {
  return bot.handleUpdate(update)
}

My problem basically is that I don´t know why but the webhook handle function is not waiting for the bot to completely handle the update

I added this to my code and everything works perfectly now:

    console.log('Finished webhook handle')
    await sleep(150)

I added this above the return statement inside the handler function and everything worked now. But it is not an elegant solution and I added 150 ms of billing time to every request, so the question is:

Why do you think it is not waiting for the bot to handle the update?

Let me show you my initBot function

const initBot = () => {
  const config = { telegram: { webhookReply: false } }
  bot = new Telegraf<BotContext>(process.env.BOT_TOKEN, config)
  const wizardsStage = new Scenes.Stage<any>([])
  const store = Mongo({
    url: process.env.DATABASE_URL,
    database: process.env.SESSION_DATABASE_NAME,
  })

  bot.use(checkUserType)
  bot.use(allowedUsers)

  bot.start(ctx => {
    console.log('start bot')
    return ctx.reply('Menú Principal', ctx.customState.isSalesman ? SalesmanMainmenuKeyboard : MainmenuKeyboard)
  })
  bot.hears(UserInteractionConstants.MAIN_MENU, ctx => {
    return ctx.reply('Menú Principal', ctx.customState.isSalesman ? SalesmanMainmenuKeyboard : MainmenuKeyboard)
  })
  initBrandsRoutes(bot, wizardsStage)
  initModulesRoutes(bot, wizardsStage)
  initInventoriesRoutes(bot, wizardsStage)
  initProductsRoutes(bot, wizardsStage)
  initCurrenciesRoutes(bot, wizardsStage)
  initSalesRoutes(bot, wizardsStage)
  initUsersRoutes(bot, wizardsStage)
  initPaymentsRoutes(bot, wizardsStage)
  initDoubtsRoutes(bot, wizardsStage)
  initSettingsRoutes(bot, wizardsStage)

  bot.use(session({ store }))
  bot.use(wizardsStage.middleware())
}

Now inside initCurrenciesRoute function (this is just an example of how it is implemented all routes for each entity)

export const initCurrenciesRoutes = (bot: Telegraf<BotContext>, wizardsStage: WizardsStageType) => {
  registerScenes(wizardsStage)
  bot.hears(UserInteractionConstants.CURRENCIES_MENU, ctx => {
    ctx.reply('Menú divisas', ctx.customState.isAdmin ? CurrencyActionsKeyboard : SalesmanCurrencyActionsKeyboard)
  })
  bot.hears(UserInteractionConstants.CURRENCY_INCREASE_ACTION, ctx => {
    ctx.reply('Incrementar divisas', CurrencyIncreaseKeyboard)
  })
  bot.hears(UserInteractionConstants.CURRENCY_DECREASE_ACTION, ctx => {
    ctx.reply('Decrementar divisas', CurrencyDecreaseKeyboard)
  })
  bot.hears(UserInteractionConstants.CURRENCY_EXCHANGE_ACTION, ctx => {
    ctx.reply('Intercambiar divisas', CurrencyExchangeKeyboard)
  })
  wizardsStage.hears(UserInteractionConstants.CURRENCY_QUERY_ACTION, async ctx => {
    console.log(`Inside ${UserInteractionConstants.CURRENCY_QUERY_ACTION}`);
    const customState: BotState = (ctx as any).customState
    if (customState.isAdmin) {
      ctx.reply('Consultar divisas', CurrencyQueryKeyboard)
    } else if (customState.isSalesman) {
      ctx.scene.enter(SceneIDS.QUERY_CURRENCIES_SALESMAN)
    }
  })
  bot.command('query_currencies', ctx => {
    const customState: BotState = (ctx as any).customState
    if (customState.isAdmin) {
      ctx.reply('Consultar divisas', CurrencyQueryKeyboard)
    } else if (customState.isSalesman) {
      ctx.scene.enter(SceneIDS.QUERY_CURRENCIES_SALESMAN)
    }
  })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions