当前位置: 首页 > news >正文

php:代码中怎么搭建一个类似linux系统的crontab服务

一、前言

        最近使用自己搭建的php框架写一些东西,需要用到异步脚本任务的执行,但是是因为自己搭建的框架没有现成的机制,所以想自己搭建一个类似linux系统的crontab服务的功能。

        因为如果直接使用linux crontab的服务配置起来很麻烦,如果不了解的人接手,也不知道你配置了crontab,后续拆分生产和测试环境也会很复杂,不能一套代码包含所有。

二、配置文件

        先在相关配置目录下放一个配置文件,例如:config/crontab.ini,里面配置如下结构,其中需要注意的是request_uri参数,这个参数是各自框架中使用命令行形式执行任务的命令,可以根据自己的框架进行修改。

例:我目前的框架执行命令形式是:

php index.php request_uri="/cli_Test/test"

;【使用说明】
;1、检测机制:每分钟自动检测一次该配置
;
;2、参数说明
;request_uri:为执行任务的命令行
;time:控制启动时间,分别为分、时、日、月、周
;proc_total:运行脚本的进程数
;ip_limit:服务器ip限制(多个ip英文,分隔)[test]
request_uri = "/cli_Test/test"
time = "0 3 * * *"
proc_total = "1"
;ip_limit = 10.235.62.241

注:

        time:配置方式是一比一复制的linux crontab配置

        proc_total:支持多个进程执行任务的方式,比如队列消费要启用多个进程消费就很方便,并且会自动检测执行任务的进程是否存在,存在不会重复启动。

        ip_limit:有时候集群服务器太多,但是你只想单台机器执行,可以使用该配置,限制执行的服务器ip是什么,也可以配置多个。

三、监控相关类

  1、配置读取类,可以解析上述配置文件结构

<?php
/*** 配置信息读取类** @package Comm*/
class Config {private static $_config = array();/*** 读取配置信息** @param  string $path   节点路径,第一个是文件名,使用点号分隔。如:"app","app.product.test"* @return array|string*/public static function get($path) {if(!isset(self::$_config[$path])) {$arr = explode('.', $path);try {$conf = parse_ini_file(APP_PATH . 'config/'.$arr[0].'.ini', true);} catch (Exception $e) {}if (!empty($conf)) {if (isset($arr[1]) && !isset($conf[$arr[1]])) {throw new Exception("读取的配置信息不存在,path: " . $path);                }if (isset($arr[1])) $conf = $conf[$arr[1]];if (isset($arr[2]) && !isset($conf[$arr[2]])) {throw new Exception("读取的配置信息不存在,path: " . $path);                }if (isset($arr[2])) $conf = $conf[$arr[2]];}if (!isset($conf) || is_null($conf)) {throw new Exception("读取的配置信息不存在,path: " . $path);                }self::$_config[$path] = $conf;}return self::$_config[$path];}
}

2、任务监控类

注:其中需要注意的是shell方法的内容,如果自己的框架不适用这种执行命令方式,可以更改为自己框架的命令。

<?php
namespace app\controllers\Cli;/*** Crontab监控* * 注:切勿轻易修改*/
class MonitorController
{/*** 检查计划任务*/public function index() {$appEnv = \Context::param("APP_ENV");//获取运行环境$appEnvParam = !empty($appEnv) ? "&APP_ENV=".$appEnv : "";echo "\033[35mCheck Crontab:\r\n\033[0m";$config = $this->getConfig();foreach ($config as $key => $value) {if (!$this->checkTime(time(), $value['time'])) {echo "{$key}:[IGNORE]\r\n";continue;}$ip_limit = isset($value['ip_limit']) ? explode(',',$value['ip_limit']) : false;for ($i = 1; $i <= $value['proc_total']; ++$i) {$request_uri = "{$value['request_uri']}?proc_total={$value['proc_total']}&proc_num={$i}{$appEnvParam}";//检查进程是否存在$shell = $this->shell($request_uri);$num   = $this->shell_proc_num($shell);echo "{$key}_{$i}:";if ($num >= 1) { //进程已存在echo "\033[33m[RUNING]\033[0m";} else {  //进程不存在,操作if($ip_limit){if(in_array(\Util::getServerIp(),$ip_limit)){echo "\033[32m[OK]\033[0m";$this->shell_cmd($request_uri);}else{echo "\033[32m[IP LIMIT]\033[0m";}}else{echo "\033[32m[OK]\033[0m";$this->shell_cmd($request_uri);}}echo "\r\n";}}}/*** 获取crontab配置* * @return	array*/public function getConfig() {return \Config::get('crontab');}/*** 检查是否该执行crontab了* * @param	int		$curr_datetime	当前时间* @param	string	$timeStr		时间配置* @return	boolean*/protected function checkTime($curr_datetime, $timeStr) {$time = explode(' ', $timeStr);if (count($time) != 5) {return false;}$month  = date("n", $curr_datetime); // 没有前导0$day    = date("j", $curr_datetime); // 没有前导0$hour   = date("G", $curr_datetime);$minute = (int)date("i", $curr_datetime);$week   = date("w", $curr_datetime); // w 0~6, 0:sunday  6:saturdayif ($this->isAllow($week, $time[4], 7, 0) &&$this->isAllow($month, $time[3], 12) &&$this->isAllow($day, $time[2], 31, 1) &&$this->isAllow($hour, $time[1], 24) &&$this->isAllow($minute, $time[0], 60)) {return true;}return false;}/*** 检查是否允许执行* * @param	mixed	$needle			数值* @param	mixed	$str			要检查的数据* @param	int		$TotalCounts	单位内最大数* @param	int		$start			单位开始值(默认为0)* @return  type*/protected function isAllow($needle, $str, $TotalCounts, $start = 0) {if (strpos($str, ',') !== false) {$weekArray = explode(',', $str);if (in_array($needle, $weekArray))return true;return false;}$array     = explode('/', $str);$end       = $start + $TotalCounts - 1;if (isset($array[1])) {if ($array[1] > $TotalCounts)return false;$tmps = explode('-', $array[0]);if (isset($tmps[1])) {if ($tmps[0] < 0 || $end < $tmps[1])return false;$start = $tmps[0];$end   = $tmps[1];} else {if ($tmps[0] != '*')return false;}if (0 == (($needle - $start) % $array[1]))return true;return false;}$tmps = explode('-', $array[0]);if (isset($tmps[1])) {if ($tmps[0] < 0 || $end < $tmps[1])return false;if ($needle >= $tmps[0] && $needle <= $tmps[1])return true;return false;} else {if ($tmps[0] == '*' || $tmps[0] == $needle)return true;return false;}}/*** 执行Shell命令** @param   string  $request_uri*/public function shell_cmd($request_uri) {if (IS_WIN) {$cmd = $this->shell($request_uri);pclose(popen("start /B " . $cmd, "r"));}else{$cmd = $this->shell($request_uri) . " > /dev/null &";$pp  = @popen($cmd, 'r');@pclose($pp);}}/*** 获取Shell执行命令** @param   string  $request_uri* @return  string*/public function shell($request_uri) {return PHP_BIN . ' ' . rtrim(APP_PATH, '/') . "/index.php request_uri=\"{$request_uri}\"";}/*** 检查指定shell命令进程数** @param   string  $shell  shell命令* @return  int*/public function shell_proc_num($shell) {if (IS_WIN) {// Windows 环境下的逻辑if (!extension_loaded('com_dotnet')) {die("COM extension is not installed or loaded.");}$num = 0;$shell = str_replace([' ', '\\'], ['', '/'], $shell);$computer = ".";$obj = new \COM('winmgmts:{impersonationLevel=impersonate}!\\\\' . $computer . '\\root\\cimv2');$processes = $obj->ExecQuery("SELECT * FROM Win32_Process");foreach ($processes as $process) {$line = str_replace([' ', '\\'], ['', '/'], $process->CommandLine);if (strpos($line, $shell) !== false) {$num++;}}return $num;} else {$shell = str_replace(array('-', '"'), array('\-', ''), $shell);// $shell = preg_quote($shell);$shell = str_replace("\?", '?', $shell);$cmd = "ps -ef | grep -v 'grep' |grep \"{$shell}\"| wc -l";$pp  = @popen($cmd, 'r');$num = trim(@fread($pp, 512)) + 0;@pclose($pp);return $num;}}
}

四、执行初始化脚本

1、init.sh,这个脚本主要是把监控任务类的执行方式写入到了linux中的crontab服务,后续就不用管了。

2、后续想要增加执行的任务,可以直接在crontab.ini中增加即可。

#开启crond
/sbin/service crond start#追加写入crontab监控
phpBin=$1
projectPath=$2
appEnv=$3
if [[ "$phpBin" == "" || "$projectPath" == "" ]]; thenecho "请先输入【php bin路径】和【项目根目录路径】"exit
fiif [[ "$appEnv" != "pro" && "$appEnv" != "dev" ]]; thenecho "请输入环境变量参数:pro生产环境 或 dev测试环境"exit
fiif [[ ! -e "$phpBin" ]]; thenecho "【php bin路径】不正确,可尝试使用which php来获取bin路径"exit
fiif [[ ! -e "$projectPath/index.php" ]]; thenecho "【项目根目录路径】不正确"exit
ficrontabl=`crontab -l | grep "$phpBin" | grep "$projectPath" | grep  "request_uri" | grep "cli_monitor"`
if [ -z "$crontabl" ]; thenecho "* * * * * $phpBin $projectPath/index.php request_uri='/cli_monitor?APP_ENV=$appEnv'" >> /var/spool/cron/rootecho -e "cli_monitor write \033[32m[SUCCESS]\033[0m"
elseecho -e "cli_monitor already exist \033[32m[SUCCESS]\033[0m"
fi

相关文章:

php:代码中怎么搭建一个类似linux系统的crontab服务

一、前言 最近使用自己搭建的php框架写一些东西&#xff0c;需要用到异步脚本任务的执行&#xff0c;但是是因为自己搭建的框架没有现成的机制&#xff0c;所以想自己搭建一个类似linux系统的crontab服务的功能。 因为如果直接使用linux crontab的服务配置起来很麻烦&#xff0…...

【LeetCode: 958. 二叉树的完全性检验 + bfs + 二叉树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

MinDoc 安装与部署

下载可执行文件 mindoc mindoc_linux_amd64.zip 上传并解压压缩包 cd /opt mkdir mindoc cd mindocunzip mindoc_linux_amd64.zip 创建数据库 CREATE DATABASE mindoc_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; 配置数据库 将解压目录下 conf/app.conf.exam…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(基础组件实现)

目录 基础组件实现 如何将图像和文字显示到OLED上 如何绘制图像 如何绘制文字 如何获取字体&#xff1f; 如何正确的访问字体 如何抽象字体 如何绘制字符串 绘制方案 文本绘制 更加方便的绘制 字体附录 ascii 6x8字体 ascii 8 x 16字体 基础组件实现 我们现在离手…...

windows系统如何检查是否开启了mongodb服务

windows系统如何检查是否开启了mongodb服务&#xff01;我们有很多软件开发&#xff0c;网站开发时候需要使用到这个mongodb数据库&#xff0c;下面我们看看&#xff0c;如何在windows系统内排查&#xff0c;是否已经启动了本地服务。 在 Windows 系统上&#xff0c;您可以通过…...

VS安卓仿真器下载失败怎么办?

如果网络不稳定&#xff0c;则VS的安卓仿真器很容易下载失败&#xff0c;如下 Downloaded file <USER_HOME>\AppData\Local\Temp\xamarin-android-sdk\x86_64-35_r08.zip not found for Android SDK archive https://dl.google.com/android/repository/sys-img/google_a…...

计算机网络一点事(24)

TCP可靠传输&#xff0c;流量控制 可靠传输&#xff1a;每字节对应一个序号 累计确认&#xff1a;收到ack则正确接收 返回ack推迟确认&#xff08;不超过0.5s&#xff09; 两种ack&#xff1a;专门确认&#xff08;只有首部无数据&#xff09; 捎带确认&#xff08;带数据…...

视频拼接,拼接时长版本

目录 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg imageio&#xff0c;适合视频较短 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg import subprocess import glob import os from nats…...

制造企业的成本核算

一、生产成本与制造费用的区别 (1)生产成本,是直接用于产品生产,构成产品实体的材料成本。 包括企业在生产经营过程中实际消耗的原材料、辅助材料、备品备件、外购半成品、燃料、动力包装物以及其它直接材料,和直接参加产品生产的工人工资,以及按生产工人的工资总额和规…...

doris:高并发导入优化(Group Commit)

在高频小批量写入场景下&#xff0c;传统的导入方式存在以下问题&#xff1a; 每个导入都会创建一个独立的事务&#xff0c;都需要经过 FE 解析 SQL 和生成执行计划&#xff0c;影响整体性能每个导入都会生成一个新的版本&#xff0c;导致版本数快速增长&#xff0c;增加了后台…...

LLMs之WebRAG:STORM/Co-STORM的简介、安装和使用方法、案例应用之详细攻略

LLMs之WebRAG&#xff1a;STORM/Co-STORM的简介、安装和使用方法、案例应用之详细攻略 目录 STORM系统简介 1、Co-STORM 2、更新新闻 STORM系统安装和使用方法 1、安装 pip安装 直接克隆GitHub仓库 2、模型和数据集 两个数据集 FreshWiki数据集 WildSeek数据集 支持…...

鸿蒙HarmonyOS实战-ArkUI动画(页面转场动画)_鸿蒙arkui tab 切换动画

PageTransitionExit({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number}) 在HarmonyOS中&#xff0c;PageTransitionEnter和PageTransitionExit是用于控制页面切换动画的参数。它们分别表示页面进入和退出时的动画。1. type&#xff08;动画类型…...

图漾相机-ROS2-SDK-Ubuntu版本编译(新版本)

文章目录 前言1.Camport ROS2 SDK 介绍1.1 Camport ROS2 SDK源文件介绍1.2 Camport ROS2 SDK工作流程1.2.1 包含头文件1.2.2 2 初始化 ROS 2 节点1.2.3 创建节点对象1.2.4 创建发布者对象并实现发布逻辑1.2.5 启动 ROS 2 1.3 ROS2 SDK环境配置与编译1.3.1 Ubuntu 20.04 下ROS2 …...

小程序的协同工作与发布

1.小程序API的三大分类 2.小程序管理的概念&#xff0c;以及成员管理两个方面 3.开发者权限说明以及如何维护项目成员 4.小程序版本...

解锁维特比算法:探寻复杂系统的最优解密码

引言 在复杂的技术世界中&#xff0c;维特比算法以其独特的魅力和广泛的应用&#xff0c;成为通信、自然语言处理、生物信息学等领域的关键技术。今天&#xff0c;让我们一同深入探索维特比算法的奥秘。 一、维特比算法的诞生背景 维特比算法由安德鲁・维特比在 1967 年提出…...

计算机网络一点事(20)

IEEE802.11 无线局域网 分类有无基础设施 星型拓扑&#xff0c;基本服务集BSS一基站多移动站&#xff0c;服务集标识符SSID不超过32b&#xff0c;可接入802.3 漫游&#xff1a;移动站从一个基本服务集切换到另一个&#xff08;类似换联WiFi&#xff09; 802.11帧&#xff1…...

java求职学习day23

MySQL 单表 & 约束 & 事务 1. DQL操作单表 1.1 创建数据库,复制表 1) 创建一个新的数据库 db2 CREATE DATABASE db2 CHARACTER SET utf8; 2) 将 db1 数据库中的 emp 表 复制到当前 db2 数据库 1.2 排序 通过 ORDER BY 子句 , 可以将查询出的结果进行排序 ( 排序只…...

Vue-cli 脚手架搭建

安装node.js 官网下载node.js安装包&#xff0c;地址&#xff1a;Node.js — Download Node.js 先在node.js即将要安装的路径下创建两个文件夹&#xff1a;node_cache&#xff08;缓存&#xff09;、node_global&#xff08;全局&#xff09; 点击安装包&#xf…...

认识小程序的基本组成结构

1.基本组成结构 2.页面的组成部分 3.json配置文件 4.app.json文件(全局配置文件&#xff09; 5.project.config.json文件 6.sitemap.json文件 7.页面的.json配置文件 通过window节点可以控制小程序的外观...

Spring Boot 热部署实现指南

在开发 Spring Bot 项目时&#xff0c;热部署功能能够显著提升开发效率&#xff0c;让开发者无需频繁重启服务器就能看到代码修改后的效果。下面为大家详细介绍一种实现 Spring Boot 热部署的方法&#xff0c;同时也欢迎大家补充其他实现形式。 步骤一、开启 IDEA 自动编译功能…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

WEB3全栈开发——面试专业技能点P4数据库

一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库&#xff0c;基于 mysql 库改进而来&#xff0c;具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点&#xff1a; 支持 Promise / async-await&#xf…...