Discuz!官方免费开源建站系统

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

X2内置计划任务分析

[复制链接]
零风 发表于 2011-3-20 23:05:49 | 显示全部楼层 |阅读模式
我们的论坛包含了很多计划任务相关的操作。
比如我们最常遇到的 每日的发贴 处理,该计划任务保证了我们能看到昨日发帖和今日发贴这样的数据。
还有比如,我们在论坛后台添加了一个到某个时间过期的广告,那么也是论坛的计划任务使得该广告到期后自动下架。

我们知道 PHP 本身是触发型语言,需要触发才能执行某个操作,而不像 linux 那样可以到指定时间执行指定的计划任务。
所以上面提到的计划任务,实际上都是需要我们触发才能执行的。

我们详细的分析下 X2 的计划任务执行的步骤,以及我们如何根据自己的需求写一个计划任务,并且加入到 X2 的系统运行中。

首先,我们看下 X2 中的核心代码 /source/core/class_core.php

discuz_core 类是我们程序的核心类,程序在执行的时候,首先会运行该类。

在该类中,我们能看到有一个方法:_init_cron() 。

该方法的代码是:
  1. function _init_cron() {
  2.                 if($this->init_cron && $this->init_setting) {
  3.                         if($this->var['cache']['cronnextrun'] <= TIMESTAMP) {
  4.                                 discuz_cron::run();
  5.                         }
  6.                 }
  7.         }
复制代码
默认情况下,我们在前面能看到 init_cron 和 init_setting 为 true,
所以这里实际上是根据我们缓存中记录的一个下次执行计划的时间和当前时间的一个对比,如果该时间小于等于当前时间,我们则执行 计划任务 的run方法。
(我们暂时先不说这个计划任务的下次执行时间是如何来的,稍后会提到,暂时只要认为需要执行计划任务即可)

同样在这个文件中,找到 discuz_cron 类,我们重点看下该类中的 run 方法:
  1. function run($cronid = 0) {

  2.                 global $_G;
  3.                 $timestamp = TIMESTAMP;
  4.                 $cron = DB::fetch_first("SELECT * FROM ".DB::table('common_cron')."
  5.                                 WHERE ".($cronid ? "cronid='$cronid'" : "available>'0' AND nextrun<='$timestamp'")."
  6.                                 ORDER BY nextrun LIMIT 1");

  7.                 $processname ='DZ_CRON_'.(empty($cron) ? 'CHECKER' : $cron['cronid']);

  8.                 if($cronid && !empty($cron)) {
  9.                         discuz_process::unlock($processname);
  10.                 }

  11.                 if(discuz_process::islocked($processname, 600)) {
  12.                         return false;
  13.                 }

  14.                 if($cron) {

  15.                         $cron['filename'] = str_replace(array('..', '/', '\\'), '', $cron['filename']);
  16.                         $cronfile = DISCUZ_ROOT.'./source/include/cron/'.$cron['filename'];

  17.                         $cron['minute'] = explode("\t", $cron['minute']);
  18.                         discuz_cron::setnextime($cron);

  19.                         @set_time_limit(1000);
  20.                         @ignore_user_abort(TRUE);

  21.                         if(!@include $cronfile) {
  22.                                 return false;
  23.                         }
  24.                 }

  25.                 discuz_cron::nextcron();
  26.                 discuz_process::unlock($processname);
  27.                 return true;
  28.         }
复制代码
这个方法如果可以指定一个 任务id ,当然也可以为空。
如果这里指定了任务的 id,就可以执行我们指定的任务,比如在后台任务列表中,手动点击执行时。就会根据这个id执行。
如果为空,会根据 表 pre_common_cron 中得到的下一次执行的任务去执行。
执行的过程采用了加锁的方式,防止在任务被同时执行,导致数据出现错误。
这个加锁的过程,可以单独分析下 discuz_process 类,这里就先不细说这个了。
执行计划任务时,会把我们事先写好的计划任务脚本载入进来,所以我们的计划任务脚本里面直接可以用 $_G 等变量。
被载入进来的脚本直接执行,执行完以后,程序会通过 setnextime 方法设置下次计划任务执行的时间。

这样,整个计划任务就连贯起来可以执行了。


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Discuz! 官方站 ( 皖ICP备16010102号 )star

GMT+8, 2024-11-17 08:28 , Processed in 0.022786 second(s), 3 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表