续集!!定时任务管理后台之多服务器集群问题 [ 2.0 版本 ]
正对解决使用YII2构建一个定时任务管理后台一些问题的后续
解决多服务器集群下, 同一个任务,同一时间在多个服务器下, 重复执行的问题, 也解决了任务耗时较长, 没跑完又发起一个新的定时任务问题,导致资源无法释放,服务器卡死
巧用乐观锁
- crontab表改动
crontab表的status字段, 值代表的意思改动为: 0正常 1运行中 2任务报错 多了一个*运行中*的状态! 注意!!
实现原理: 当任务判断为可以运行时就把就把定时任务状态调用update方法,改为1, 成功rue,失败false, 只有true的任务才能执行,反之跳过
- 注意事项, 很重要
说一下自己遇到的一些坑, 例如服务器断电
或者挂了, 那么就会导致一些进行中的任务状态没改成正常, 所以,断电了就要把定时任务的状态都恢复成正常
- 代码改动 CrontabController.php
- 定义一个类的全局常量
class CrontabController extends Controller
{
const WAIT_SYNC_TIME = 5;
.....
- 修改executeTask方法代码
private function executeTask(array $tasks)
{
if (empty($tasks)) {
return;
}
shuffle($tasks);
$pool = [];
$startExectime = $this->getCurrentTime();
$pid = getmypid();
$startDate = date('Y-m-d H:i:s');
foreach ($tasks as $k => $task) {
// 乐观锁, 上锁. 防止同一任务,重复执行,
$task->status = 1;
$isOk = $task->update(false);
if ($isOk) {
Yii::info("pid[$pid] 定时任务启动: {$task->name}, route: {$task->route}");
$pool[$k] = proc_open("php yii $task->route", [], $pipe);
}
}
// 防止同一任务,在多个机器上,重复执行
sleep(self::WAIT_SYNC_TIME);
// 回收子进程
while (count($pool)) {
foreach ($pool as $i => $result) {
$etat = proc_get_status($result);
if($etat['running'] == FALSE) {
proc_close($result);
unset($pool[$i]);
$tasks[$i]->exectime = round($this->getCurrentTime() - $startExectime - self::WAIT_SYNC_TIME, 2);
$tasks[$i]->last_rundate = $startDate;
$tasks[$i]->next_rundate = $tasks[$i]->getNextRunDate();
$tasks[$i]->status = '0';
// 任务出错
if ($etat['exitcode'] !== ExitCode::OK) {
$tasks[$i]->status = 2;
}
$tasks[$i]->save(false);
}
}
}
}
qq497012571
注册时间:2018-03-22
最后登录:2024-09-05
在线时长:22小时20分
最后登录:2024-09-05
在线时长:22小时20分
- 粉丝14
- 金钱475
- 威望30
- 积分995
共 1 条评论
WAIT_SYNC_TIME 常量是有用的, 最好保证所有服务器的服务器时间要一致