【问题标题】:telegram bot goes into infinite loop when iterating over a big list on the backend迭代后端的大列表时,电报机器人进入无限循环
【发布时间】:2023-12-02 02:09:01
【问题描述】:

你好,所以我正在尝试向我的电报机器人添加广播命令,该命令向我的所有机器人订阅者广播特定消息,其 id 保存在 mysql 数据库中,但循环似乎永远不会结束并在随机发送消息后重新启动

例如:机器人开始发送消息,然后在 987 个用户处停止,然后 一遍又一遍地重新启动循环,或者重新启动不同数量的用户

这是我正在使用的代码:

<?php
http_response_code(200);

$admin_id = ''; // my id
$bot_token = ''; // my bot token 

$message_object = json_decode(file_get_contents("php://input"),true);
$message_text = $message_object['message']['text'];


if(startsWith($message_text, '/broadcast') !== false){
    $text_to_send = trim(str_replace('/broadcast','',$message_text));
    $start_message = sendmessage($admin_id, 'Broadcasting Started', $bot_token, 'markdown');
    $start_message_id = $start_message['result']['message_id'];
    $query = mysqli_query($con, "SELECT * FROM users");
    if($query and mysqli_num_rows($query) >= 1){
        $all_users = mysqli_fetch_all($query,MYSQLI_ASSOC);
        $sent = 0;
        foreach($all_users as $user){
            $user_id = $user['userid'];
            $sent += 1;
            sendmessage($user_id,$text_to_send,$bot_token,'markdown');
            sleep(1);
            editmessage($admin_id,"Messages Sent : $sent",$bot_token,$start_message_id);
        }
        sendmessage($admin_id,'finished broadcasting '.$sent.' messages',$bot_token,'markdown');
    }
}

?>

而且我从来没有设法到达循环的末尾以获取广播完成消息并陷入无限循环

当我尝试导入超过 50 项的数据量时会发生同样的问题,因此 mysql 数据库使用与广播一相同的方法

【问题讨论】:

    标签: php telegram telegram-bot php-telegram-bot telegram-webhook


    【解决方案1】:

    我认为这是 PHP maximum execution time 的问题:默认情况下,PHP 的最大执行时间为 30 秒。 30 秒后脚本终止,并向发出初始请求的客户端(在本例中为 Telegram API)报告错误。 Telegram 看到您的脚本抛出的错误并重复相同的请求,因此脚本每 30 秒一次又一次地执行。可能的解决方案如下:

    $admin_id = '';之前添加如下代码

    set_time_limit(100); // Set the max execution time
    
    ignore_user_abort(true);
    header('Connection: close');
    flush();
    fastcgi_finish_request();
    

    此代码将立即关闭与 Telegram 的连接,因此它不必等到脚本终止,并且如果发生错误也不会再次调用脚本。使用set_time_limit(100) 函数,您可以增加执行限制(例如增加到 100 秒),这样 PHP 在您向所有人发送广播消息之前不会杀死所有内容。如果此操作花费超过 100 秒,只需增加限制或将其设置为 0,这样它就永远不会结束,因为根据 set_time_limit 文档:如果设置为零,则不施加时间限制。

    【讨论】:

    • 我已将 set_time_limit 设置为零,并且存在相同的问题,并且我的脚本始终返回响应代码 200
    • 您好,您的脚本运行一段时间后是否返回 200?无论如何,Telegram 可能有一个“最大连接时间”,之后它会关闭连接并再次发送相同的请求。您是否尝试过使用第二个代码块(以 ignore_user_abort... 开头的代码块)立即关闭与 Telegram 的连接?
    • 我试图关闭连接,但由于某种原因导致关闭循环