diff --git a/Server/README_scheduler.md b/Server/README_scheduler.md new file mode 100644 index 00000000..4c485684 --- /dev/null +++ b/Server/README_scheduler.md @@ -0,0 +1,254 @@ +# 统一任务调度器使用说明 + +## 概述 + +统一任务调度器(TaskSchedulerCommand)是一个集中管理所有定时任务的调度系统,支持: +- ✅ 单条 crontab 配置管理所有任务 +- ✅ 多进程并发执行任务 +- ✅ 自动根据 cron 表达式判断任务执行时间 +- ✅ 任务锁机制,防止重复执行 +- ✅ 完善的日志记录 + +## 安装配置 + +### 1. 配置文件 + +任务配置位于 `config/task_scheduler.php`,格式如下: + +```php +'任务标识' => [ + 'command' => '命令名称', // 必填:执行的命令 + 'schedule' => 'cron表达式', // 必填:cron表达式 + 'options' => ['--option=value'], // 可选:命令参数 + 'enabled' => true, // 可选:是否启用 + 'max_concurrent' => 1, // 可选:最大并发数 + 'timeout' => 3600, // 可选:超时时间(秒) + 'log_file' => 'custom.log', // 可选:自定义日志文件 +] +``` + +### 2. Cron 表达式格式 + +标准 cron 格式:`分钟 小时 日 月 星期` + +示例: +- `*/1 * * * *` - 每分钟执行 +- `*/5 * * * *` - 每5分钟执行 +- `*/30 * * * *` - 每30分钟执行 +- `0 2 * * *` - 每天凌晨2点执行 +- `0 3 */3 * *` - 每3天的3点执行 + +### 3. Crontab 配置 + +**只需要在 crontab 中添加一条任务:** + +```bash +# 每分钟执行一次调度器(调度器内部会根据 cron 表达式判断哪些任务需要执行) +* * * * * cd /www/wwwroot/mckb_quwanzhi_com/Server && php think scheduler:run >> /www/wwwroot/mckb_quwanzhi_com/Server/runtime/log/scheduler.log 2>&1 +``` + +### 4. 系统要求 + +- PHP >= 5.6.0 +- 推荐启用 `pcntl` 扩展以支持多进程并发(非必需,未启用时使用单进程顺序执行) + +检查 pcntl 扩展: +```bash +php -m | grep pcntl +``` + +## 使用方法 + +### 手动执行调度器 + +```bash +# 执行调度器(会自动判断当前时间需要执行的任务) +php think scheduler:run +``` + +### 查看任务配置 + +```bash +# 查看所有已注册的命令 +php think list +``` + +### 启用/禁用任务 + +编辑 `config/task_scheduler.php`,设置 `'enabled' => false` 即可禁用任务。 + +## 功能特性 + +### 1. 多进程并发执行 + +- 默认最大并发数:10 个进程 +- 自动管理进程池 +- 自动清理僵尸进程 + +### 2. 任务锁机制 + +- 每个任务在执行时会设置锁(5分钟内不重复执行) +- 防止任务重复执行 +- 锁存储在缓存中,自动过期 + +### 3. 日志记录 + +- 调度器日志:`runtime/log/scheduler.log` +- 每个任务的日志:`runtime/log/{log_file}` +- 任务执行开始和结束都有标记 + +### 4. 超时控制 + +- 默认超时时间:3600 秒(1小时) +- 可在配置中为每个任务单独设置超时时间 +- 超时后自动终止任务 + +## 配置示例 + +### 高频任务(每分钟) + +```php +'wechat_friends_active' => [ + 'command' => 'wechatFriends:list', + 'schedule' => '*/1 * * * *', + 'options' => ['--isDel=0'], + 'enabled' => true, +], +``` + +### 中频任务(每5分钟) + +```php +'device_active' => [ + 'command' => 'device:list', + 'schedule' => '*/5 * * * *', + 'options' => ['--isDel=0'], + 'enabled' => true, +], +``` + +### 每日任务 + +```php +'wechat_calculate_score' => [ + 'command' => 'wechat:calculate-score', + 'schedule' => '0 2 * * *', // 每天凌晨2点 + 'options' => [], + 'enabled' => true, +], +``` + +### 定期任务(每3天) + +```php +'sync_all_friends' => [ + 'command' => 'sync:allFriends', + 'schedule' => '0 3 */3 * *', // 每3天的3点 + 'options' => [], + 'enabled' => true, +], +``` + +## 从旧配置迁移 + +### 旧配置(多条 crontab) + +```bash +*/5 * * * * cd /path && php think device:list --isDel=0 >> log1.log 2>&1 +*/1 * * * * cd /path && php think wechatFriends:list >> log2.log 2>&1 +``` + +### 新配置(单条 crontab + 配置文件) + +**Crontab:** +```bash +* * * * * cd /path && php think scheduler:run >> scheduler.log 2>&1 +``` + +**config/task_scheduler.php:** +```php +'device_active' => [ + 'command' => 'device:list', + 'schedule' => '*/5 * * * *', + 'options' => ['--isDel=0'], + 'log_file' => 'log1.log', +], +'wechat_friends' => [ + 'command' => 'wechatFriends:list', + 'schedule' => '*/1 * * * *', + 'log_file' => 'log2.log', +], +``` + +## 监控和调试 + +### 查看调度器日志 + +```bash +tail -f runtime/log/scheduler.log +``` + +### 查看任务执行日志 + +```bash +tail -f runtime/log/crontab_device_active.log +``` + +### 检查任务是否在执行 + +```bash +# 查看进程 +ps aux | grep "php think" +``` + +### 手动测试任务 + +```bash +# 直接执行某个任务 +php think device:list --isDel=0 +``` + +## 注意事项 + +1. **时间同步**:确保服务器时间准确,调度器依赖系统时间判断任务执行时间 +2. **资源限制**:根据服务器性能调整 `maxConcurrent` 参数 +3. **日志清理**:定期清理日志文件,避免占用过多磁盘空间 +4. **任务冲突**:如果任务执行时间较长,建议调整执行频率或增加并发数 +5. **缓存依赖**:任务锁使用缓存,确保缓存服务正常运行 + +## 故障排查 + +### 任务未执行 + +1. 检查任务是否启用:`'enabled' => true` +2. 检查 cron 表达式是否正确 +3. 检查调度器是否正常运行:查看 `scheduler.log` +4. 检查任务锁:任务可能在5分钟内重复执行被跳过 + +### 任务执行失败 + +1. 查看任务日志:`runtime/log/{log_file}` +2. 检查命令是否正确:手动执行命令测试 +3. 检查权限:确保有执行权限和日志写入权限 + +### 多进程不工作 + +1. 检查 pcntl 扩展:`php -m | grep pcntl` +2. 检查系统限制:`ulimit -u` 查看最大进程数 +3. 查看调度器日志中的错误信息 + +## 性能优化建议 + +1. **合理设置并发数**:根据服务器 CPU 核心数和内存大小调整 +2. **错开高频任务**:避免所有任务在同一分钟执行 +3. **优化任务执行时间**:减少任务执行时长 +4. **使用队列**:对于耗时任务,建议使用队列异步处理 + +## 更新日志 + +### v1.0.0 (2024-01-XX) +- 初始版本 +- 支持多进程并发执行 +- 支持 cron 表达式调度 +- 支持任务锁机制 + diff --git a/Server/application/command.php b/Server/application/command.php index b5c4d0e5..ce06453b 100644 --- a/Server/application/command.php +++ b/Server/application/command.php @@ -42,4 +42,7 @@ return [ 'wechat:calculate-score' => 'app\command\CalculateWechatAccountScoreCommand', // 统一计算微信账号健康分 'wechat:update-score' => 'app\command\UpdateWechatAccountScoreCommand', // 更新微信账号评分记录 + + // 统一任务调度器 + 'scheduler:run' => 'app\command\TaskSchedulerCommand', // 统一任务调度器,支持多进程并发执行 ]; diff --git a/Server/application/command/TaskSchedulerCommand.php b/Server/application/command/TaskSchedulerCommand.php new file mode 100644 index 00000000..06a1dbaf --- /dev/null +++ b/Server/application/command/TaskSchedulerCommand.php @@ -0,0 +1,457 @@ +> /path/to/log/scheduler.log 2>&1 + */ +class TaskSchedulerCommand extends Command +{ + /** + * 任务配置 + */ + protected $tasks = []; + + /** + * 最大并发进程数 + */ + protected $maxConcurrent = 10; + + /** + * 当前运行的进程数 + */ + protected $runningProcesses = []; + + /** + * 日志目录 + */ + protected $logDir = ''; + + protected function configure() + { + $this->setName('scheduler:run') + ->setDescription('统一任务调度器,支持多进程并发执行所有定时任务'); + } + + protected function execute(Input $input, Output $output) + { + $output->writeln('=========================================='); + $output->writeln('任务调度器启动'); + $output->writeln('时间: ' . date('Y-m-d H:i:s')); + $output->writeln('=========================================='); + + // 检查是否支持 pcntl 扩展 + if (!function_exists('pcntl_fork')) { + $output->writeln('错误:系统不支持 pcntl 扩展,无法使用多进程功能'); + $output->writeln('提示:将使用单进程顺序执行任务'); + $this->maxConcurrent = 1; + } + + // 加载任务配置 + $this->tasks = Config::get('task_scheduler', []); + if (empty($this->tasks)) { + $output->writeln('错误:未找到任务配置'); + return false; + } + + // 设置日志目录 + $this->logDir = runtime_path() . 'log' . DIRECTORY_SEPARATOR; + if (!is_dir($this->logDir)) { + mkdir($this->logDir, 0755, true); + } + + // 获取当前时间 + $currentTime = time(); + $currentMinute = date('i', $currentTime); + $currentHour = date('H', $currentTime); + $currentDay = date('d', $currentTime); + $currentMonth = date('m', $currentTime); + $currentWeekday = date('w', $currentTime); // 0=Sunday, 6=Saturday + + $output->writeln("当前时间: {$currentHour}:{$currentMinute}"); + $output->writeln("已加载 " . count($this->tasks) . " 个任务配置"); + + // 筛选需要执行的任务 + $tasksToRun = []; + foreach ($this->tasks as $taskId => $task) { + if (!isset($task['enabled']) || !$task['enabled']) { + continue; + } + + if ($this->shouldRun($task['schedule'], $currentMinute, $currentHour, $currentDay, $currentMonth, $currentWeekday)) { + $tasksToRun[$taskId] = $task; + } + } + + if (empty($tasksToRun)) { + $output->writeln('当前时间没有需要执行的任务'); + return true; + } + + $output->writeln("找到 " . count($tasksToRun) . " 个需要执行的任务"); + + // 执行任务 + if ($this->maxConcurrent > 1 && function_exists('pcntl_fork')) { + $this->executeConcurrent($tasksToRun, $output); + } else { + $this->executeSequential($tasksToRun, $output); + } + + // 清理僵尸进程 + $this->cleanupZombieProcesses(); + + $output->writeln('=========================================='); + $output->writeln('任务调度器执行完成'); + $output->writeln('=========================================='); + + return true; + } + + /** + * 判断任务是否应该执行 + * + * @param string $schedule cron表达式,格式:分钟 小时 日 月 星期 + * @param int $minute 当前分钟 + * @param int $hour 当前小时 + * @param int $day 当前日期 + * @param int $month 当前月份 + * @param int $weekday 当前星期 + * @return bool + */ + protected function shouldRun($schedule, $minute, $hour, $day, $month, $weekday) + { + $parts = preg_split('/\s+/', trim($schedule)); + if (count($parts) < 5) { + return false; + } + + list($scheduleMinute, $scheduleHour, $scheduleDay, $scheduleMonth, $scheduleWeekday) = $parts; + + // 解析分钟 + if (!$this->matchCronField($scheduleMinute, $minute)) { + return false; + } + + // 解析小时 + if (!$this->matchCronField($scheduleHour, $hour)) { + return false; + } + + // 解析日期 + if (!$this->matchCronField($scheduleDay, $day)) { + return false; + } + + // 解析月份 + if (!$this->matchCronField($scheduleMonth, $month)) { + return false; + } + + // 解析星期(注意:cron中0和7都表示星期日) + if ($scheduleWeekday !== '*') { + $scheduleWeekday = str_replace('7', '0', $scheduleWeekday); + if (!$this->matchCronField($scheduleWeekday, $weekday)) { + return false; + } + } + + return true; + } + + /** + * 匹配cron字段 + * + * @param string $field cron字段表达式 + * @param int $value 当前值 + * @return bool + */ + protected function matchCronField($field, $value) + { + // 通配符 + if ($field === '*') { + return true; + } + + // 列表(逗号分隔) + if (strpos($field, ',') !== false) { + $values = explode(',', $field); + foreach ($values as $v) { + if ($this->matchCronField(trim($v), $value)) { + return true; + } + } + return false; + } + + // 范围(如 1-5) + if (strpos($field, '-') !== false) { + list($start, $end) = explode('-', $field); + return $value >= (int)$start && $value <= (int)$end; + } + + // 步长(如 */5 或 0-59/5) + if (strpos($field, '/') !== false) { + $parts = explode('/', $field); + $base = $parts[0]; + $step = (int)$parts[1]; + + if ($base === '*') { + return $value % $step === 0; + } else { + // 处理范围步长,如 0-59/5 + if (strpos($base, '-') !== false) { + list($start, $end) = explode('-', $base); + if ($value >= (int)$start && $value <= (int)$end) { + return ($value - (int)$start) % $step === 0; + } + return false; + } else { + return $value % $step === 0; + } + } + } + + // 精确匹配 + return (int)$field === $value; + } + + /** + * 并发执行任务(多进程) + * + * @param array $tasks 任务列表 + * @param Output $output 输出对象 + */ + protected function executeConcurrent($tasks, Output $output) + { + $output->writeln('使用多进程并发执行任务(最大并发数:' . $this->maxConcurrent . ')'); + + foreach ($tasks as $taskId => $task) { + // 等待可用进程槽 + while (count($this->runningProcesses) >= $this->maxConcurrent) { + $this->waitForProcesses(); + usleep(100000); // 等待100ms + } + + // 检查任务是否已经在运行(防止重复执行) + $lockKey = "scheduler_task_lock:{$taskId}"; + $lockTime = Cache::get($lockKey); + if ($lockTime && (time() - $lockTime) < 300) { // 5分钟内不重复执行 + $output->writeln("任务 {$taskId} 正在运行中,跳过"); + continue; + } + + // 创建子进程 + $pid = pcntl_fork(); + + if ($pid == -1) { + // 创建进程失败 + $output->writeln("创建子进程失败:{$taskId}"); + Log::error("任务调度器:创建子进程失败", ['task' => $taskId]); + continue; + } elseif ($pid == 0) { + // 子进程:执行任务 + $this->runTask($taskId, $task); + exit(0); + } else { + // 父进程:记录子进程PID + $this->runningProcesses[$pid] = [ + 'task_id' => $taskId, + 'start_time' => time(), + ]; + $output->writeln("启动任务:{$taskId} (PID: {$pid})"); + + // 设置任务锁 + Cache::set($lockKey, time(), 600); // 10分钟过期 + } + } + + // 等待所有子进程完成 + while (!empty($this->runningProcesses)) { + $this->waitForProcesses(); + usleep(500000); // 等待500ms + } + } + + /** + * 顺序执行任务(单进程) + * + * @param array $tasks 任务列表 + * @param Output $output 输出对象 + */ + protected function executeSequential($tasks, Output $output) + { + $output->writeln('使用单进程顺序执行任务'); + + foreach ($tasks as $taskId => $task) { + $output->writeln("执行任务:{$taskId}"); + $this->runTask($taskId, $task); + } + } + + /** + * 执行单个任务 + * + * @param string $taskId 任务ID + * @param array $task 任务配置 + */ + protected function runTask($taskId, $task) + { + $startTime = microtime(true); + $logFile = $this->logDir . ($task['log_file'] ?? "scheduler_{$taskId}.log"); + + // 确保日志目录存在 + $logDir = dirname($logFile); + if (!is_dir($logDir)) { + mkdir($logDir, 0755, true); + } + + // 构建命令 + $thinkPath = root_path() . 'think'; + $command = "php {$thinkPath} {$task['command']}"; + if (!empty($task['options'])) { + foreach ($task['options'] as $option) { + $command .= ' ' . escapeshellarg($option); + } + } + + // 添加日志重定向 + $command .= " >> " . escapeshellarg($logFile) . " 2>&1"; + + // 记录任务开始 + $logMessage = "\n" . str_repeat('=', 60) . "\n"; + $logMessage .= "任务开始执行: {$taskId}\n"; + $logMessage .= "执行时间: " . date('Y-m-d H:i:s') . "\n"; + $logMessage .= "命令: {$command}\n"; + $logMessage .= str_repeat('=', 60) . "\n"; + file_put_contents($logFile, $logMessage, FILE_APPEND); + + // 执行命令 + $descriptorspec = [ + 0 => ['file', (PHP_OS_FAMILY === 'Windows' ? 'NUL' : '/dev/null'), 'r'], // stdin + 1 => ['file', $logFile, 'a'], // stdout + 2 => ['file', $logFile, 'a'], // stderr + ]; + + $process = @proc_open($command, $descriptorspec, $pipes, root_path()); + + if (is_resource($process)) { + // 关闭管道 + if (isset($pipes[0])) @fclose($pipes[0]); + if (isset($pipes[1])) @fclose($pipes[1]); + if (isset($pipes[2])) @fclose($pipes[2]); + + // 设置超时 + $timeout = $task['timeout'] ?? 3600; + $startWaitTime = time(); + + // 等待进程完成或超时 + while (true) { + $status = proc_get_status($process); + + if (!$status['running']) { + break; + } + + // 检查超时 + if ((time() - $startWaitTime) > $timeout) { + if (function_exists('proc_terminate')) { + proc_terminate($process, SIGTERM); + // 等待进程终止 + sleep(2); + $status = proc_get_status($process); + if ($status['running']) { + // 强制终止 + proc_terminate($process, SIGKILL); + } + } + Log::warning("任务执行超时", [ + 'task' => $taskId, + 'timeout' => $timeout, + ]); + break; + } + + usleep(500000); // 等待500ms + } + + // 关闭进程 + proc_close($process); + } else { + // 如果 proc_open 失败,尝试直接执行(后台执行) + if (PHP_OS_FAMILY === 'Windows') { + pclose(popen("start /B " . $command, "r")); + } else { + exec($command . ' > /dev/null 2>&1 &'); + } + } + + $endTime = microtime(true); + $duration = round($endTime - $startTime, 2); + + // 记录任务完成 + $logMessage = "\n" . str_repeat('=', 60) . "\n"; + $logMessage .= "任务执行完成: {$taskId}\n"; + $logMessage .= "完成时间: " . date('Y-m-d H:i:s') . "\n"; + $logMessage .= "执行时长: {$duration} 秒\n"; + $logMessage .= str_repeat('=', 60) . "\n"; + file_put_contents($logFile, $logMessage, FILE_APPEND); + + Log::info("任务执行完成", [ + 'task' => $taskId, + 'duration' => $duration, + ]); + } + + /** + * 等待进程完成 + */ + protected function waitForProcesses() + { + foreach ($this->runningProcesses as $pid => $info) { + $status = 0; + $result = pcntl_waitpid($pid, $status, WNOHANG); + + if ($result == $pid || $result == -1) { + // 进程已结束 + unset($this->runningProcesses[$pid]); + + $duration = time() - $info['start_time']; + Log::info("子进程执行完成", [ + 'pid' => $pid, + 'task' => $info['task_id'], + 'duration' => $duration, + ]); + } + } + } + + /** + * 清理僵尸进程 + */ + protected function cleanupZombieProcesses() + { + if (!function_exists('pcntl_waitpid')) { + return; + } + + $status = 0; + while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) > 0) { + // 清理僵尸进程 + } + } +} + diff --git a/Server/config/task_scheduler.php b/Server/config/task_scheduler.php new file mode 100644 index 00000000..7fa7ea37 --- /dev/null +++ b/Server/config/task_scheduler.php @@ -0,0 +1,301 @@ + [ + // 'command' => '命令名称', // 必填:执行的 ThinkPHP 命令(见 application/command.php) + // 'schedule' => 'cron表达式', // 必填:cron 表达式,如 '*/5 * * * *' 表示每5分钟 + // 'options' => ['--option=value'], // 可选:命令参数(原来 crontab 里的 --xxx=yyy) + // 'enabled' => true, // 可选:是否启用,默认 true + // 'max_concurrent'=> 1, // 可选:单任务最大并发数(目前由调度器统一控制,可预留) + // 'timeout' => 3600, // 可选:超时时间(秒),默认 3600 + // 'log_file' => 'custom.log', // 可选:日志文件名,默认使用任务标识 + // ] + + // =========================== + // 高频任务(每分钟或更频繁) + // =========================== + + // 同步微信好友列表(未删除好友),用于保持系统中好友数据实时更新 + 'wechat_friends_active' => [ + 'command' => 'wechatFriends:list', + 'schedule' => '*/1 * * * *', // 每1分钟 + 'options' => ['--isDel=0'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_wechatFriends_active.log', + ], + + // 拉取“添加好友任务”列表,驱动自动加好友的任务队列 + 'friend_task' => [ + 'command' => 'friendTask:list', + 'schedule' => '*/1 * * * *', // 每1分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_friendTask.log', + ], + + // 同步微信好友私聊消息列表,写入消息表,供客服工作台使用 + 'message_friends' => [ + 'command' => 'message:friendsList', + 'schedule' => '*/1 * * * *', // 每1分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_messageFriends.log', + ], + + // 同步微信群聊消息列表,写入消息表,供群聊记录与风控分析 + 'message_chatroom' => [ + 'command' => 'message:chatroomList', + 'schedule' => '*/1 * * * *', // 每1分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_messageChatroom.log', + ], + + // 客服端消息提醒任务,负责给在线客服推送新消息通知 + 'kf_notice' => [ + 'command' => 'kf:notice', + 'schedule' => '*/1 * * * *', // 每1分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'kf_notice.log', + ], + + // =========================== + // 中频任务(每 2-5 分钟) + // =========================== + + // 同步微信设备列表(未删除设备),用于设备管理与监控 + 'device_active' => [ + 'command' => 'device:list', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => ['--isDel=0'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_device_active.log', + ], + + // 同步微信群聊列表(未删除群),用于群管理与后续任务分配 + 'wechat_chatroom_active' => [ + 'command' => 'wechatChatroom:list', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => ['--isDel=0'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_wechatChatroom_active.log', + ], + + // 同步微信群成员列表(群好友),维持群成员明细数据 + 'group_friends' => [ + 'command' => 'groupFriends:list', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_groupFriends.log', + ], + + // 同步“微信客服列表”,获取绑定到公司的微信号,用于工作台与分配规则 + 'wechat_list' => [ + 'command' => 'wechatList:list', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_wechatList.log', + ], + + // 同步公司账号列表(企业/租户账号),供后台管理与统计 + 'account_list' => [ + 'command' => 'account:list', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_account.log', + ], + + // 内容采集任务,将外部或设备内容同步到系统内容库 + 'content_collect' => [ + 'command' => 'content:collect', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_contentCollect.log', + ], + + // 工作台:自动点赞好友/客户朋友圈,提高账号活跃度 + 'workbench_auto_like' => [ + 'command' => 'workbench:autoLike', + 'schedule' => '*/6 * * * *', // 每6分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_workbench_autoLike.log', + ], + + // 工作台:自动建群任务,按规则批量创建微信群 + 'workbench_group_create' => [ + 'command' => 'workbench:groupCreate', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'workbench_groupCreate.log', + ], + + // 工作台:自动导入通讯录到系统,生成加粉/建群等任务 + 'workbench_import_contact' => [ + 'command' => 'workbench:import-contact', + 'schedule' => '*/5 * * * *', // 每5分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'import_contact.log', + ], + + // =========================== + // 低频任务(每 2 分钟) + // =========================== + + // 清洗并同步微信原始数据到存客宝业务表(数据治理任务) + 'sync_wechat_data' => [ + 'command' => 'sync:wechatData', + 'schedule' => '*/2 * * * *', // 每2分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'sync_wechat_data.log', + ], + + // 工作台:流量分发任务,把流量池中的线索按规则分配给微信号或员工 + 'workbench_traffic_distribute' => [ + 'command' => 'workbench:trafficDistribute', + 'schedule' => '*/2 * * * *', // 每2分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'traffic_distribute.log', + ], + + // 工作台:朋友圈同步任务,拉取并落库朋友圈内容 + 'workbench_moments' => [ + 'command' => 'workbench:moments', + 'schedule' => '*/2 * * * *', // 每2分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'workbench_moments.log', + ], + + // 预防性切换好友任务,监控频繁/风控风险,自动切换加人对象,保护微信号 + 'switch_friends' => [ + 'command' => 'switch:friends', + 'schedule' => '*/2 * * * *', // 每2分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'switch_friends.log', + ], + + // =========================== + // 低频任务(每 30 分钟) + // =========================== + + // 拉取设备通话记录(语音/电话),用于质检、统计或标签打分 + 'call_recording' => [ + 'command' => 'call-recording:list', + 'schedule' => '*/30 * * * *', // 每30分钟 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'call_recording.log', + ], + + // =========================== + // 每日 / 每几天任务 + // =========================== + + // 每日 1:00 同步“已删除设备”列表,补齐历史状态 + 'device_deleted' => [ + 'command' => 'device:list', + 'schedule' => '0 1 * * *', // 每天1点 + 'options' => ['--isDel=1'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_device_deleted.log', + ], + + // 每日 1:10 同步“已停用设备”列表,更新停用状态 + 'device_stopped' => [ + 'command' => 'device:list', + 'schedule' => '10 1 * * *', // 每天1:10 + 'options' => ['--isDel=2'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_device_stopped.log', + ], + + // 每日 1:30 同步“已删除微信好友”,用于历史恢复与报表 + 'wechat_friends_deleted' => [ + 'command' => 'wechatFriends:list', + 'schedule' => '30 1 * * *', // 每天1:30 + 'options' => ['--isDel=1'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_wechatFriends_deleted.log', + ], + + // 每日 1:30 同步“已删除微信群聊”,用于统计与留痕 + 'wechat_chatroom_deleted' => [ + 'command' => 'wechatChatroom:list', + 'schedule' => '30 1 * * *', // 每天1:30 + 'options' => ['--isDel=1'], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'crontab_wechatChatroom_deleted.log', + ], + + // 每日 2:00 统一计算所有微信账号健康分(基础分 + 动态分) + 'wechat_calculate_score' => [ + 'command' => 'wechat:calculate-score', + 'schedule' => '0 2 * * *', // 每天2点 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'calculate_score.log', + ], + + // 每 3 天执行的全量任务 + + // 每 3 天 3:00 全量同步所有在线好友,做一次大规模校准 + 'sync_all_friends' => [ + 'command' => 'sync:allFriends', + 'schedule' => '0 3 */3 * *', // 每3天的3点 + 'options' => [], + 'enabled' => true, + 'max_concurrent' => 1, + 'log_file' => 'all_friends.log', + ], + + // 已禁用的任务(注释掉的任务) + // 'workbench_group_push' => [ + // 'command' => 'workbench:groupPush', + // 'schedule' => '*/2 * * * *', + // 'options' => [], + // 'enabled' => false, + // 'log_file' => 'workbench_groupPush.log', + // ], +]; +