You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP共享主机上每5秒运行短信队列任务?

解决共享主机上每5秒执行短信队列脚本的问题

你遇到的情况在共享主机环境里特别常见——Cron最小间隔卡着5分钟,又没法装Supervisor这类进程管理工具,要实现高频任务确实得换个思路。下面给你两个可行的方案,结合你的现有代码来调整:

方案1:PHP无限循环脚本(生产环境推荐)

这个思路是用Cron每5分钟启动一个持久运行的PHP脚本,脚本内部自己做循环,每5秒执行一次短信发送逻辑。这样既绕开了Cron的间隔限制,又不需要额外工具支持。

改造你的代码:

<?php
// 关闭脚本执行时间限制,让脚本可以一直运行
set_time_limit(0);
// 即使浏览器/客户端断开连接,脚本也继续执行
ignore_user_abort(true);

// 设定每次任务执行的间隔(5秒)
$interval = 5;

// 无限循环执行任务
while (true) {
    // 先初始化数据库连接(记得替换成你的实际连接参数)
    $mysqli = mysqli_connect("你的数据库主机", "用户名", "密码", "数据库名");
    if (!$mysqli) {
        error_log("数据库连接失败: " . mysqli_connect_error());
        sleep($interval);
        continue;
    }

    // 关键优化:加状态标记避免重复发送!
    // 假设你给crbsms_queue表加了status字段,默认值为pending表示待发送
    $query_sch = "SELECT * FROM crbsms_queue 
                  LEFT JOIN crbusers ON crbsms_queue.user_id = crbusers.user_id
                  WHERE crbsms_queue.status = 'pending'";
    $sch_result = mysqli_query($mysqli, $query_sch);

    if ($sch_result) {
        foreach ($sch_result as $value) {
            $phone = $value['phones'];
            $sender = $value['sender'];
            $message = $value['message'];
            $user_id = $value['user_id'];
            $id = $value['id'];
            $token = $value["access_token"];
            $link_id = NULL;
            $correlator = "$id";
            $endpoint = 'https://example.com/delivery-url.php';
            $version = "v1";

            // 先标记这条短信为「正在发送」,防止其他循环进程重复处理
            mysqli_query($mysqli, "UPDATE crbsms_queue SET status = 'sending' WHERE id = $id");

            try {
                $instance = new BongaTech($token, $version);
                $sms = new Sms($sender, $phone, $message, $correlator, null, $endpoint);
                $instance->sendBatchSMS($sms);
                
                // 发送成功后标记为「已发送」
                mysqli_query($mysqli, "UPDATE crbsms_queue SET status = 'sent' WHERE id = $id");
            } catch (Exception $e) {
                // 发送失败可以标记为「发送失败」,方便后续排查或重试
                $errorMsg = mysqli_real_escape_string($mysqli, $e->getMessage());
                mysqli_query($mysqli, "UPDATE crbsms_queue SET status = 'failed', error = '$errorMsg' WHERE id = $id");
                error_log("短信ID $id 发送失败: " . $e->getMessage());
            }
        }
        mysqli_free_result($sch_result);
    } else {
        error_log("查询短信队列失败: " . mysqli_error($mysqli));
    }

    // 关闭数据库连接,避免资源泄漏
    mysqli_close($mysqli);

    // 等待5秒后执行下一轮任务
    sleep($interval);
}
?>

部署步骤:

  1. 把上面的脚本保存为process_sms_queue.php,上传到你的共享主机目录
  2. 在Cron面板里添加任务,每5分钟启动一次这个脚本:
    */5 * * * * php /你的主机路径/process_sms_queue.php > /dev/null 2>&1
    
    这样就算旧脚本因为某种原因意外终止,Cron也会每5分钟补一个新的,保证任务持续运行。

注意事项:

  • 必须加短信状态标记,否则多个脚本实例可能重复发送同一条短信
  • 共享主机一般有进程数量限制,Cron设为5分钟间隔比较稳妥,避免同时跑太多进程
  • 可以通过error_log记录关键日志,方便后续排查问题

方案2:HTML页面+定时刷新(仅临时测试用)

如果只是临时需要高频执行任务,可以写个简单的HTML页面,用浏览器定时刷新来触发脚本:

<!DOCTYPE html>
<html>
<head>
    <!-- 每5秒自动刷新页面 -->
    <meta http-equiv="refresh" content="5">
</head>
<body>
    <?php
    // 这里放你的短信发送逻辑(记得加状态标记避免重复)
    $mysqli = mysqli_connect("你的数据库主机", "用户名", "密码", "数据库名");
    // ... 省略查询和发送代码 ...
    ?>
</body>
</html>

这个方案的缺点很明显:必须一直开着浏览器,一旦浏览器关闭或网络断开,任务就停止了,只适合临时测试,绝对不能用于生产环境。


内容的提问来源于stack exchange,提问作者Edward Muss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 06:42:32