You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
5.4 KiB
210 lines
5.4 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | Niucloud-admin 企业快速开发的多应用管理平台
|
|
// +----------------------------------------------------------------------
|
|
// | 官方网址:https://www.niucloud.com
|
|
// +----------------------------------------------------------------------
|
|
// | niucloud团队 版权所有 开源版本可自由商用
|
|
// +----------------------------------------------------------------------
|
|
// | Author: Niucloud Team
|
|
// +----------------------------------------------------------------------
|
|
|
|
namespace core\base;
|
|
|
|
use think\facade\Log;
|
|
|
|
/**
|
|
* 定时任务基类,提供执行锁机制和统一日志
|
|
*/
|
|
abstract class BaseScheduleJob extends BaseJob
|
|
{
|
|
/**
|
|
* 任务名称(用于锁文件命名)
|
|
* @var string
|
|
*/
|
|
protected $jobName = 'schedule_job';
|
|
|
|
/**
|
|
* 锁定时间(秒),默认5分钟
|
|
* @var int
|
|
*/
|
|
protected $lockTimeout = 300;
|
|
|
|
/**
|
|
* 是否启用每日执行标记
|
|
* @var bool
|
|
*/
|
|
protected $enableDailyFlag = false;
|
|
|
|
/**
|
|
* 最终执行的方法,子类需要实现
|
|
* @return mixed
|
|
*/
|
|
abstract protected function executeJob();
|
|
|
|
/**
|
|
* 主执行方法,添加锁机制
|
|
* @return mixed
|
|
*/
|
|
public function doJob()
|
|
{
|
|
$lockFile = $this->getLockFilePath();
|
|
|
|
// 检查执行锁
|
|
if ($this->isLocked($lockFile)) {
|
|
Log::write($this->jobName . '任务正在执行中,跳过');
|
|
return $this->getSkippedResult('locked');
|
|
}
|
|
|
|
// 检查每日执行标记
|
|
if ($this->enableDailyFlag && $this->isExecutedToday()) {
|
|
Log::write($this->jobName . '今天已经执行过,跳过');
|
|
return $this->getSkippedResult('already_executed_today');
|
|
}
|
|
|
|
// 创建锁文件
|
|
$this->createLock($lockFile);
|
|
|
|
try {
|
|
Log::write('开始执行' . $this->jobName . '任务');
|
|
|
|
// 执行具体任务
|
|
$result = $this->executeJob();
|
|
|
|
// 创建每日执行标记
|
|
if ($this->enableDailyFlag) {
|
|
$this->createDailyFlag();
|
|
}
|
|
|
|
Log::write($this->jobName . '任务执行完成');
|
|
return $result;
|
|
|
|
} catch (\Exception $e) {
|
|
Log::write($this->jobName . '任务执行失败:' . $e->getMessage());
|
|
return $this->getFailedResult($e->getMessage());
|
|
} finally {
|
|
// 删除锁文件
|
|
$this->removeLock($lockFile);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取锁文件路径
|
|
* @return string
|
|
*/
|
|
protected function getLockFilePath()
|
|
{
|
|
return runtime_path() . $this->jobName . '.lock';
|
|
}
|
|
|
|
/**
|
|
* 检查是否被锁定
|
|
* @param string $lockFile
|
|
* @return bool
|
|
*/
|
|
protected function isLocked($lockFile)
|
|
{
|
|
return file_exists($lockFile) && (time() - filemtime($lockFile)) < $this->lockTimeout;
|
|
}
|
|
|
|
/**
|
|
* 创建锁文件
|
|
* @param string $lockFile
|
|
*/
|
|
protected function createLock($lockFile)
|
|
{
|
|
file_put_contents($lockFile, time());
|
|
}
|
|
|
|
/**
|
|
* 删除锁文件
|
|
* @param string $lockFile
|
|
*/
|
|
protected function removeLock($lockFile)
|
|
{
|
|
if (file_exists($lockFile)) {
|
|
unlink($lockFile);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查今天是否已经执行过
|
|
* @return bool
|
|
*/
|
|
protected function isExecutedToday()
|
|
{
|
|
$today = date('Y-m-d');
|
|
$flagFile = runtime_path() . $this->jobName . '_' . $today . '.flag';
|
|
return file_exists($flagFile);
|
|
}
|
|
|
|
/**
|
|
* 创建每日执行标记
|
|
*/
|
|
protected function createDailyFlag()
|
|
{
|
|
$today = date('Y-m-d');
|
|
$flagFile = runtime_path() . $this->jobName . '_' . $today . '.flag';
|
|
file_put_contents($flagFile, time());
|
|
}
|
|
|
|
/**
|
|
* 获取跳过执行的结果
|
|
* @param string $reason
|
|
* @return array
|
|
*/
|
|
protected function getSkippedResult($reason)
|
|
{
|
|
return [
|
|
'status' => 'skipped',
|
|
'reason' => $reason,
|
|
'job_name' => $this->jobName,
|
|
'timestamp' => time()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取执行失败的结果
|
|
* @param string $error
|
|
* @return array
|
|
*/
|
|
protected function getFailedResult($error)
|
|
{
|
|
return [
|
|
'status' => 'failed',
|
|
'error' => $error,
|
|
'job_name' => $this->jobName,
|
|
'timestamp' => time()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取执行成功的结果
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
protected function getSuccessResult($data = [])
|
|
{
|
|
return array_merge([
|
|
'status' => 'success',
|
|
'job_name' => $this->jobName,
|
|
'timestamp' => time()
|
|
], $data);
|
|
}
|
|
|
|
/**
|
|
* 清理过期的标记文件(超过7天)
|
|
*/
|
|
protected function cleanupOldFlags()
|
|
{
|
|
$runtimePath = runtime_path();
|
|
$pattern = $runtimePath . $this->jobName . '_*.flag';
|
|
$files = glob($pattern);
|
|
|
|
foreach ($files as $file) {
|
|
if (file_exists($file) && (time() - filemtime($file)) > 7 * 24 * 3600) { // 7天
|
|
unlink($file);
|
|
}
|
|
}
|
|
}
|
|
}
|