接单工单支持任务时限,超时自动判定失败并处置

This commit is contained in:
yml2213
2026-08-01 19:02:57 +08:00
parent 66193c5d59
commit 23ad60a1ef
18 changed files with 681 additions and 61 deletions
@@ -2,10 +2,11 @@ import { logError, logInfo, logWarn } from '../../utils/logger.js'
import { createHttpError } from '../../utils/http.js'
import type { JsonObject } from '../../types/json.js'
import {
getCloudtentaclesHealthJob,
getScheduledJobById,
getScheduledJobsConfig,
} from './config-service.js'
import { runCloudtentaclesHealthJob } from './cloudtentacles-health-job.js'
import { runWorkOrderTimeoutJob } from './work-order-timeout-job.js'
const timers = new Map<string, NodeJS.Timeout>()
const jobStates = new Map<string, JsonObject>()
@@ -67,14 +68,20 @@ export async function runScheduledJobNow(jobId: unknown) {
const result = await runJob(job, { manual: true })
if (getScheduledJobsConfig().enabled !== false) {
const latestJob = getCloudtentaclesHealthJob(getScheduledJobsConfig())
if (latestJob.enabled === true) {
scheduleJob(latestJob, Math.max(60, Number(latestJob.intervalSeconds || 300)) * 1000)
}
rescheduleJob(job)
}
return result
}
function rescheduleJob(job: JsonObject) {
const jobId = String(job.id || '').trim()
if (!jobId) return
const latestJob = getScheduledJobById(jobId)
if (!latestJob || latestJob.enabled !== true) return
const intervalMs = Math.max(60, Number(latestJob.intervalSeconds || 60)) * 1000
scheduleJob(latestJob, intervalMs)
}
function scheduleJob(job: JsonObject, delayMs: number) {
const jobId = String(job.id || '').trim()
if (!jobId) {
@@ -90,10 +97,7 @@ function scheduleJob(job: JsonObject, delayMs: number) {
const timer = setTimeout(() => {
timers.delete(jobId)
void runJob(job).finally(() => {
const latestJob = getCloudtentaclesHealthJob(getScheduledJobsConfig())
if (latestJob.enabled === true) {
scheduleJob(latestJob, Math.max(60, Number(latestJob.intervalSeconds || 300)) * 1000)
}
rescheduleJob(job)
})
}, delayMs)
@@ -126,25 +130,27 @@ async function runJob(job: JsonObject, { manual = false }: { manual?: boolean }
try {
const result = await dispatchJob(job)
const summary =
result && typeof result === 'object' ? (result as JsonObject) : {}
updateJobState(jobId, {
running: false,
lastFinishedAt: new Date().toISOString(),
lastStatus: result?.status || 'ok',
lastMessage: result?.message || '执行完成',
lastAsset: typeof result?.asset === 'number' ? result.asset : null,
lastThreshold: typeof result?.threshold === 'number' ? result.threshold : null,
lastAccounts: Array.isArray(result?.accounts) ? result.accounts : [],
lastAccountCount: Number(result?.accountCount || 0),
lastCheckedCount: Number(result?.checkedCount || 0),
lastOkCount: Number(result?.okCount || 0),
lastLowAssetCount: Number(result?.lowAssetCount || 0),
lastFailedCount: Number(result?.failedCount || 0),
lastStatus: String(summary.status || 'ok'),
lastMessage: String(summary.message || '执行完成'),
lastAsset: typeof summary.asset === 'number' ? summary.asset : null,
lastThreshold: typeof summary.threshold === 'number' ? summary.threshold : null,
lastAccounts: Array.isArray(summary.accounts) ? summary.accounts : [],
lastAccountCount: Number(summary.accountCount || 0),
lastCheckedCount: Number(summary.checkedCount || 0),
lastOkCount: Number(summary.okCount || 0),
lastLowAssetCount: Number(summary.lowAssetCount || 0),
lastFailedCount: Number(summary.failedCount || 0),
lastManual: manual,
})
logInfo('[scheduler]', '定时任务执行完成', {
jobId,
type: job.type,
status: result?.status || 'ok',
status: String(summary.status || 'ok'),
})
return result
} catch (error) {
@@ -173,6 +179,9 @@ function dispatchJob(job: JsonObject) {
if (job.type === 'cloudtentacles_health') {
return runCloudtentaclesHealthJob(job)
}
if (job.type === 'work_order_timeout') {
return runWorkOrderTimeoutJob(job)
}
throw createHttpError(`不支持的定时任务类型:${job.type}`, {
statusCode: 400,