返回首页

延迟触发

某些场景下,您可能需要延迟执行某些操作,比如在订单支付后延迟发送通知,或者定时清理数据。

使用场景

  • 订单支付后延迟发送邮件通知
  • 用户注册后延迟发送欢迎消息
  • 定时清理过期数据
  • 异步处理耗时任务

实现方式

方式1:使用数据库队列

// 添加延迟任务到队列
function addDelayTask($hook, $data, $delay_seconds) {
    $db = Database::getInstance();
    $execute_time = time() + $delay_seconds;
    
    $db->add('delay_tasks', [
        'hook' => $hook,
        'data' => json_encode($data),
        'execute_time' => $execute_time,
        'status' => 0,
        'create_time' => time()
    ]);
}

// 示例:订单支付后5分钟发送通知
function on_order_paid($order_id, $order) {
    addDelayTask('send_order_notification', [
        'order_id' => $order_id,
        'email' => $order['email']
    ], 300); // 延迟300秒
}
addAction('order_paid', 'on_order_paid');

// 处理延迟任务(通过定时任务调用)
function processDelayTasks() {
    $db = Database::getInstance();
    $now = time();
    
    $tasks = $db->fetch_all("SELECT * FROM " . DB_PREFIX . "delay_tasks 
        WHERE status = 0 AND execute_time <= {$now} LIMIT 10");
    
    foreach ($tasks as $task) {
        $data = json_decode($task['data'], true);
        
        // 执行钩子
        doAction($task['hook'], $data);
        
        // 标记完成
        $db->query("UPDATE " . DB_PREFIX . "delay_tasks 
            SET status = 1 WHERE id = {$task['id']}");
    }
}

方式2:使用 JavaScript 延迟

对于前端展示类的延迟,可以使用 JavaScript:

// 页面加载后3秒显示弹窗
setTimeout(function() {
    layer.open({
        title: '温馨提示',
        content: '欢迎访问本站!'
    });
}, 3000);

方式3:使用系统定时任务

对于需要定期执行的任务,建议配置系统定时任务(Cron):

# Linux Crontab 示例
# 每分钟执行一次延迟任务处理
* * * * * php /path/to/dcshop/cron.php process_delay_tasks

# 每天凌晨2点清理过期数据
0 2 * * * php /path/to/dcshop/cron.php clean_expired_data

注意事项

  • 延迟任务不保证精确执行时间,可能有几秒到几分钟的误差
  • 重要的业务逻辑不要依赖延迟执行,应该在主流程中完成
  • 延迟任务应该具有幂等性,即多次执行结果相同
  • 建议记录任务执行日志,便于排查问题