Telegram Bot (Telegraf) 陷入无限循环
Telegram Bot (Telegraf) stuck in infinite loop
我名为 status 的函数发送有关存储在 Firebase 实时数据库 中的产品的信息。当用户向我的机器人询问状态时,Firebase 函数会从数据库中获取数据,然后针对分配给用户的 每个 产品发回电报消息。对于某些用户,这可能 需要一些时间 甚至 2 分钟。
当 1st 用户第一次向机器人询问状态和机器人功能时 运行 一切正常。
但是当 第二次 用户在首次调用 机器人功能时 请求状态(当功能仍然 运行为第一个用户) 第一次调用运行 重新开始,在第一次调用完成后,最后处理第二次调用。
当 3rd 用户在旧调用未完成时调用函数时,所有内容 堆叠在 上,最后所有内容循环 until所有函数调用结束。因为 bot 几乎有 2000 个活跃用户 上面的问题 运行 进入了“无限”循环,因为不断有一些用户为自己调用“状态”。
这种情况导致用户收到几乎无限数量的消息。
我在 Firebase 上使用 JavaScript 和 Node 12。
const { Telegraf, Markup } = require('telegraf');
const { telegrafThrottler } = require('telegraf-throttler');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const debug = true;
admin.initializeApp(); // initialize firebase-admin
const bot = new Telegraf(functions.config().telegram_token.key); // initialize Telegraf bot
const throttler = telegrafThrottler(); // Telegraf Throttler
bot.use(throttler);
/**
*
bot.command('some_commands_here', async (ctx) => {
const nothing = 'THIS IS NOT IMPORTANT';
});
bot.command(...) more commands
*/
/** action with infinite loop problem */
bot.action('status', async (ctx) => {
const uid = ctx.update.callback_query.from.id;
let userData = await getUserAccountData(admin, uid); // get some data from firebase realtime db
if (userData !== null) {
let userProducts = await getUserProducts(admin, uid); // get some data from firebase realtime db
if (userProducts !== null) {
// userProducts contain even 200 items for one user
for (const [privateProductId, privateProductData] of Object.entries(userProducts)) {
// some not important logic that create message and keyboard context
// after this bot send informations about every product (can be even 200 messages )
await bot.telegram.sendMessage(uid, `${message}`, {
parse_mode: 'html',
reply_markup: keyboard.reply_markup,
});
}
}
}
// some not important logic if userData / userProducts are null
});
/** Default response for undefinded msg/commands */
bot.on('message', (ctx) => ctx.reply("Use /help if You don't know commands!"));
/** bot catch errors here */
bot.catch((err, ctx) => {
if (debug) {functions.logger.error(`Bot Catched ERROR: ${err}`);}
bot.telegram.sendMessage(123456789, `Bot Catched ERROR: ${err}`);
});
const runtimeOpts = {
timeoutSeconds: 500,
memory: '1GB',
};
exports.bot = functions.region('europe-west3').runWith(runtimeOpts).https.onRequest((req, res) => {
// bot.handleUpdate(req.body, res);
bot.handleUpdate(req.body, res).catch((err) => {
if (debug) {functions.logger.error(err);}
});
});
OK终于找到原因了^^
我的代码中遗漏了 process.once,因为该函数被执行了不止一次。
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));
我名为 status 的函数发送有关存储在 Firebase 实时数据库 中的产品的信息。当用户向我的机器人询问状态时,Firebase 函数会从数据库中获取数据,然后针对分配给用户的 每个 产品发回电报消息。对于某些用户,这可能 需要一些时间 甚至 2 分钟。
当 1st 用户第一次向机器人询问状态和机器人功能时 运行 一切正常。
但是当 第二次 用户在首次调用 机器人功能时 请求状态(当功能仍然 运行为第一个用户) 第一次调用运行 重新开始,在第一次调用完成后,最后处理第二次调用。
当 3rd 用户在旧调用未完成时调用函数时,所有内容 堆叠在 上,最后所有内容循环 until所有函数调用结束。因为 bot 几乎有 2000 个活跃用户 上面的问题 运行 进入了“无限”循环,因为不断有一些用户为自己调用“状态”。
这种情况导致用户收到几乎无限数量的消息。
我在 Firebase 上使用 JavaScript 和 Node 12。
const { Telegraf, Markup } = require('telegraf');
const { telegrafThrottler } = require('telegraf-throttler');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const debug = true;
admin.initializeApp(); // initialize firebase-admin
const bot = new Telegraf(functions.config().telegram_token.key); // initialize Telegraf bot
const throttler = telegrafThrottler(); // Telegraf Throttler
bot.use(throttler);
/**
*
bot.command('some_commands_here', async (ctx) => {
const nothing = 'THIS IS NOT IMPORTANT';
});
bot.command(...) more commands
*/
/** action with infinite loop problem */
bot.action('status', async (ctx) => {
const uid = ctx.update.callback_query.from.id;
let userData = await getUserAccountData(admin, uid); // get some data from firebase realtime db
if (userData !== null) {
let userProducts = await getUserProducts(admin, uid); // get some data from firebase realtime db
if (userProducts !== null) {
// userProducts contain even 200 items for one user
for (const [privateProductId, privateProductData] of Object.entries(userProducts)) {
// some not important logic that create message and keyboard context
// after this bot send informations about every product (can be even 200 messages )
await bot.telegram.sendMessage(uid, `${message}`, {
parse_mode: 'html',
reply_markup: keyboard.reply_markup,
});
}
}
}
// some not important logic if userData / userProducts are null
});
/** Default response for undefinded msg/commands */
bot.on('message', (ctx) => ctx.reply("Use /help if You don't know commands!"));
/** bot catch errors here */
bot.catch((err, ctx) => {
if (debug) {functions.logger.error(`Bot Catched ERROR: ${err}`);}
bot.telegram.sendMessage(123456789, `Bot Catched ERROR: ${err}`);
});
const runtimeOpts = {
timeoutSeconds: 500,
memory: '1GB',
};
exports.bot = functions.region('europe-west3').runWith(runtimeOpts).https.onRequest((req, res) => {
// bot.handleUpdate(req.body, res);
bot.handleUpdate(req.body, res).catch((err) => {
if (debug) {functions.logger.error(err);}
});
});
OK终于找到原因了^^
我的代码中遗漏了 process.once,因为该函数被执行了不止一次。
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));