Files
ulthon_admin/extend/base/common/service/TimerServiceBase.php
augushong a47bbb2c6a fix(timer): 自动记录执行日志并捕获结果
Add execute() wrapper in TimerControllerBase that wraps do() with logStart/logEnd, captures return value to result field. Change site URL routing from /do to /execute with task_name injection. Add result field to system_timer_log scheme.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-26 18:33:45 +08:00

173 lines
5.4 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace base\common\service;
use app\admin\model\SystemTimerConfig;
use app\common\model\VirtualModel;
use app\common\service\HostService;
class TimerServiceBase
{
protected $taskList = null;
/**
* 将配置文件中的定时任务同步到数据库.
* 仅新增不存在的记录,标记孤立记录,不覆盖 run_type/status.
*/
public static function syncConfigToDatabase(): void
{
$config_list = include app_file_path('common/command/timer/config.php');
// 提取唯一的任务名称(并发扩展会产生同名配置,需去重)
$config_names = [];
foreach ($config_list as $config_item) {
$item = static::initConfigItem($config_item);
$name = (string) $item['name'];
if ($name !== '' && !in_array($name, $config_names, true)) {
$config_names[] = $name;
}
}
// 查询已有记录
$existing = SystemTimerConfig::column('task_name');
$now = time();
// 新增:配置中有但数据库中没有的
$new_names = array_diff($config_names, $existing);
foreach ($new_names as $name) {
SystemTimerConfig::create([
'task_name' => $name,
'run_type' => 'auto',
'status' => 1,
'is_synced' => 1,
'create_time' => $now,
'update_time' => $now,
]);
}
// 已存在且仍在配置中:仅更新 is_synced=1不动 run_type/status
$still_exists = array_intersect($existing, $config_names);
foreach ($still_exists as $name) {
SystemTimerConfig::where('task_name', $name)
->update([
'is_synced' => 1,
'update_time' => $now,
]);
}
// 已存在但不在配置中:标记为孤立
$orphaned = array_diff($existing, $config_names);
foreach ($orphaned as $name) {
SystemTimerConfig::where('task_name', $name)
->update([
'is_synced' => 0,
'update_time' => $now,
]);
}
}
public static function generateAllTaskInstanceList()
{
$config_list = include app_file_path('common/command/timer/config.php');
$task_list = [];
foreach ($config_list as $config_item) {
if ($config_item['name'] == 'http_demo' && !env('adminsystem.is_demo', false)) {
continue;
}
$task_list = array_merge($task_list, static::generateTaskInstanceFromConfig($config_item));
}
return $task_list;
}
public function generateAllRequestList()
{
if ($this->taskList === null) {
$this->taskList = static::generateAllTaskInstanceList();
}
$request_list = array_filter($this->taskList, function ($item) {
return $item['type'] == 'site';
});
return $request_list;
}
public function generateAllCallList()
{
if ($this->taskList === null) {
$this->taskList = static::generateAllTaskInstanceList();
}
$request_list = array_filter($this->taskList, function ($item) {
return $item['type'] == 'call';
});
return $request_list;
}
public static function generateTaskInstanceFromConfig($config_item)
{
$config_item = static::initConfigItem($config_item);
$request_list = [];
$concurrency = $config_item['concurrency'];
for ($i = 0; $i < $concurrency; $i++) {
$target = $config_item['target'];
$params = [
'concurrency_id' => $i,
'concurrency_count' => $concurrency,
'host_id' => HostService::getNodeId(),
'task_name' => $config_item['name'],
];
// 处理target
if ($config_item['type'] == 'site') {
$target_info = parse_url($target);
// 将 /do 替换为 /execute用于日志包裹
if (isset($target_info['path'])) {
$target_info['path'] = preg_replace('#/do$#', '/execute', $target_info['path']);
}
$query_params = [];
if (isset($target_info['query'])) {
parse_str($target_info['query'], $query_params);
}
$query_params = array_merge($query_params, $params);
$target_info['query'] = http_build_query($query_params);
$target = unparse_url($target_info);
} elseif ($config_item['type'] == 'call') {
$target = $config_item['target'];
}
$new_config_item = clone $config_item;
$new_config_item['target'] = $target;
$new_config_item['concurrency_id'] = $i;
$request_list[] = $new_config_item;
}
return $request_list;
}
public static function initConfigItem($config)
{
$default = [
'name' => 'http_demo',
'type' => 'site',
'target' => '',
'frequency' => 600,
'concurrency' => 1,
'run_type' => 'auto',
];
$data = array_merge($default, $config);
if ($data['frequency'] < 0) {
$data['frequency'] = 0;
}
$model_timer = new VirtualModel($data);
return $model_timer;
}
}