fix(api): 修复墙检测任务超时占用与状态展示
为超过 5 分钟未领取或未上报的 pending/checking 任务自动标记失败,避免长期占用 active 状态并阻塞新检测 同时区分前端“等待节点领取”和“检测中”展示, 补充跳过原因提示,并更新相关测试与文档
This commit is contained in:
@@ -8,6 +8,8 @@ use Illuminate\Support\Collection;
|
||||
|
||||
class ServerGfwCheckService
|
||||
{
|
||||
private const ACTIVE_TASK_TIMEOUT_SECONDS = 300;
|
||||
|
||||
private const TASK_STATUS = [
|
||||
ServerGfwCheck::STATUS_PENDING,
|
||||
ServerGfwCheck::STATUS_CHECKING,
|
||||
@@ -17,6 +19,8 @@ class ServerGfwCheckService
|
||||
{
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $ids))));
|
||||
$servers = Server::whereIn('id', $ids)->get()->keyBy('id');
|
||||
$this->expireStaleActiveTasks($ids);
|
||||
$activeLookup = $this->activeTaskServerLookup($ids);
|
||||
$started = [];
|
||||
$skipped = [];
|
||||
|
||||
@@ -46,6 +50,15 @@ class ServerGfwCheckService
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($activeLookup[(int) $server->id])) {
|
||||
$skipped[] = [
|
||||
'id' => $id,
|
||||
'status' => ServerGfwCheck::STATUS_SKIPPED,
|
||||
'reason' => '已有检测任务等待节点领取或上报',
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$check = $this->createCheck($server, $adminUserId);
|
||||
$started[] = [
|
||||
'id' => $server->id,
|
||||
@@ -74,12 +87,8 @@ class ServerGfwCheckService
|
||||
}
|
||||
|
||||
$servers = $query->get();
|
||||
$activeServerIds = ServerGfwCheck::whereIn('server_id', $servers->pluck('id'))
|
||||
->whereIn('status', self::TASK_STATUS)
|
||||
->pluck('server_id')
|
||||
->map(fn ($id) => (int) $id)
|
||||
->all();
|
||||
$activeLookup = array_flip($activeServerIds);
|
||||
$expired = $this->expireStaleActiveTasks($servers->pluck('id'));
|
||||
$activeLookup = $this->activeTaskServerLookup($servers->pluck('id'));
|
||||
$started = [];
|
||||
$skipped = [];
|
||||
|
||||
@@ -105,7 +114,8 @@ class ServerGfwCheckService
|
||||
'started' => $started,
|
||||
'skipped' => $skipped,
|
||||
'total' => $servers->count(),
|
||||
'active' => count($activeServerIds),
|
||||
'active' => count($activeLookup),
|
||||
'expired' => $expired,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -169,6 +179,8 @@ class ServerGfwCheckService
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->expireStaleActiveTasks([$node->id]);
|
||||
|
||||
$check = ServerGfwCheck::where('server_id', $node->id)
|
||||
->whereIn('status', self::TASK_STATUS)
|
||||
->orderByDesc('id')
|
||||
@@ -185,6 +197,47 @@ class ServerGfwCheckService
|
||||
return $this->formatTask($check->refresh());
|
||||
}
|
||||
|
||||
private function activeTaskServerLookup($serverIds): array
|
||||
{
|
||||
$ids = collect($serverIds)
|
||||
->map(fn ($id) => (int) $id)
|
||||
->filter()
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($ids->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_flip(ServerGfwCheck::whereIn('server_id', $ids)
|
||||
->whereIn('status', self::TASK_STATUS)
|
||||
->pluck('server_id')
|
||||
->map(fn ($id) => (int) $id)
|
||||
->all());
|
||||
}
|
||||
|
||||
private function expireStaleActiveTasks($serverIds): int
|
||||
{
|
||||
$ids = collect($serverIds)
|
||||
->map(fn ($id) => (int) $id)
|
||||
->filter()
|
||||
->unique()
|
||||
->values();
|
||||
|
||||
if ($ids->isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ServerGfwCheck::whereIn('server_id', $ids)
|
||||
->whereIn('status', self::TASK_STATUS)
|
||||
->where('updated_at', '<=', now()->subSeconds(self::ACTIVE_TASK_TIMEOUT_SECONDS))
|
||||
->update([
|
||||
'status' => ServerGfwCheck::STATUS_FAILED,
|
||||
'error_message' => '墙检测任务超时:节点端未领取或未上报结果',
|
||||
'checked_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function reportResult(Server $node, array $payload): bool
|
||||
{
|
||||
$checkId = (int) ($payload['check_id'] ?? 0);
|
||||
|
||||
Reference in New Issue
Block a user