后端迁移定时任务服务

This commit is contained in:
yml
2026-05-21 16:34:06 +08:00
parent 1c760f1dd3
commit f130bdba78
4 changed files with 32 additions and 22 deletions
@@ -1,5 +1,3 @@
// @ts-check
import { getCloudtentaclesAsset } from '../platforms/cloudtentacles/catalog-service.js' import { getCloudtentaclesAsset } from '../platforms/cloudtentacles/catalog-service.js'
import { getCloudtentaclesSourceConfig } from '../platforms/cloudtentacles/source-config-service.js' import { getCloudtentaclesSourceConfig } from '../platforms/cloudtentacles/source-config-service.js'
import { getCloudtentaclesSessionState } from '../platforms/cloudtentacles/session-state-service.js' import { getCloudtentaclesSessionState } from '../platforms/cloudtentacles/session-state-service.js'
@@ -8,7 +6,9 @@ import {
notifyCloudtentaclesAuthExpired, notifyCloudtentaclesAuthExpired,
} from '../notification/domain-notifications.js' } from '../notification/domain-notifications.js'
export async function runCloudtentaclesHealthJob(job) { type JsonObject = Record<string, any>
export async function runCloudtentaclesHealthJob(job: JsonObject) {
const source = getCloudtentaclesSourceConfig() const source = getCloudtentaclesSourceConfig()
const session = getCloudtentaclesSessionState() const session = getCloudtentaclesSessionState()
const token = String(session.token || '').trim() const token = String(session.token || '').trim()
@@ -1,5 +1,3 @@
// @ts-check
import fs from 'node:fs' import fs from 'node:fs'
import path from 'node:path' import path from 'node:path'
@@ -8,6 +6,8 @@ import { PROJECT_ROOT } from '../../config/runtime.js'
const SCHEDULED_JOBS_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'scheduled-jobs.json') const SCHEDULED_JOBS_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'scheduled-jobs.json')
const CLOUDTENTACLES_HEALTH_JOB_ID = 'cloudtentacles-health' const CLOUDTENTACLES_HEALTH_JOB_ID = 'cloudtentacles-health'
type JsonObject = Record<string, any>
export function getScheduledJobsFilePath() { export function getScheduledJobsFilePath() {
return SCHEDULED_JOBS_FILE_PATH return SCHEDULED_JOBS_FILE_PATH
} }
@@ -16,14 +16,14 @@ export function getScheduledJobsConfig() {
return loadScheduledJobsConfigFromFile() return loadScheduledJobsConfigFromFile()
} }
export function saveScheduledJobsConfig(rawValue) { export function saveScheduledJobsConfig(rawValue: unknown) {
const normalized = normalizeScheduledJobsConfig(rawValue) const normalized = normalizeScheduledJobsConfig(rawValue)
fs.mkdirSync(path.dirname(SCHEDULED_JOBS_FILE_PATH), { recursive: true }) fs.mkdirSync(path.dirname(SCHEDULED_JOBS_FILE_PATH), { recursive: true })
fs.writeFileSync(SCHEDULED_JOBS_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8') fs.writeFileSync(SCHEDULED_JOBS_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
return normalized return normalized
} }
export function getCloudtentaclesHealthJob(config = getScheduledJobsConfig()) { export function getCloudtentaclesHealthJob(config: JsonObject = getScheduledJobsConfig()) {
return (Array.isArray(config.jobs) ? config.jobs : []) return (Array.isArray(config.jobs) ? config.jobs : [])
.find((item) => String(item.id || '').trim() === CLOUDTENTACLES_HEALTH_JOB_ID) .find((item) => String(item.id || '').trim() === CLOUDTENTACLES_HEALTH_JOB_ID)
|| createDefaultCloudtentaclesHealthJob() || createDefaultCloudtentaclesHealthJob()
@@ -42,7 +42,7 @@ function loadScheduledJobsConfigFromFile() {
} }
} }
function normalizeScheduledJobsConfig(rawValue) { function normalizeScheduledJobsConfig(rawValue: unknown) {
const source = isPlainObject(rawValue) ? rawValue : {} const source = isPlainObject(rawValue) ? rawValue : {}
const rawJobs = Array.isArray(source.jobs) ? source.jobs : [] const rawJobs = Array.isArray(source.jobs) ? source.jobs : []
const jobs = rawJobs.map((item) => normalizeScheduledJob(item)).filter(Boolean) const jobs = rawJobs.map((item) => normalizeScheduledJob(item)).filter(Boolean)
@@ -58,7 +58,7 @@ function normalizeScheduledJobsConfig(rawValue) {
} }
} }
function normalizeScheduledJob(rawValue) { function normalizeScheduledJob(rawValue: unknown) {
if (!isPlainObject(rawValue)) { if (!isPlainObject(rawValue)) {
return null return null
} }
@@ -71,7 +71,7 @@ function normalizeScheduledJob(rawValue) {
return normalizeCloudtentaclesHealthJob(rawValue) return normalizeCloudtentaclesHealthJob(rawValue)
} }
function normalizeCloudtentaclesHealthJob(rawValue) { function normalizeCloudtentaclesHealthJob(rawValue: JsonObject) {
const config = isPlainObject(rawValue.config) ? rawValue.config : {} const config = isPlainObject(rawValue.config) ? rawValue.config : {}
return { return {
@@ -108,7 +108,7 @@ function createDefaultCloudtentaclesHealthJob() {
} }
} }
function normalizeRangeInteger(value, fallback, min, max) { function normalizeRangeInteger(value: unknown, fallback: number, min: number, max: number) {
const parsed = Number(value) const parsed = Number(value)
if (!Number.isInteger(parsed)) { if (!Number.isInteger(parsed)) {
return fallback return fallback
@@ -117,6 +117,6 @@ function normalizeRangeInteger(value, fallback, min, max) {
return Math.min(max, Math.max(min, parsed)) return Math.min(max, Math.max(min, parsed))
} }
function isPlainObject(value) { function isPlainObject(value: unknown): value is JsonObject {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
} }
@@ -1,5 +1,3 @@
// @ts-check
import { logError, logInfo, logWarn } from '../../utils/logger.js' import { logError, logInfo, logWarn } from '../../utils/logger.js'
import { import {
getCloudtentaclesHealthJob, getCloudtentaclesHealthJob,
@@ -7,8 +5,10 @@ import {
} from './config-service.js' } from './config-service.js'
import { runCloudtentaclesHealthJob } from './cloudtentacles-health-job.js' import { runCloudtentaclesHealthJob } from './cloudtentacles-health-job.js'
const timers = new Map() type JsonObject = Record<string, any>
const jobStates = new Map()
const timers = new Map<string, NodeJS.Timeout>()
const jobStates = new Map<string, JsonObject>()
export function startScheduledJobs() { export function startScheduledJobs() {
reloadScheduledJobs() reloadScheduledJobs()
@@ -26,7 +26,7 @@ export function reloadScheduledJobs() {
const config = getScheduledJobsConfig() const config = getScheduledJobsConfig()
if (config.enabled === false) { if (config.enabled === false) {
logInfo('[scheduler]', '定时任务系统已停用') logInfo('[scheduler]', '定时任务系统已停用', {})
return return
} }
@@ -48,7 +48,7 @@ export function getScheduledJobRuntimeStates() {
return Array.from(jobStates.values()) return Array.from(jobStates.values())
} }
export async function runScheduledJobNow(jobId) { export async function runScheduledJobNow(jobId: unknown) {
const config = getScheduledJobsConfig() const config = getScheduledJobsConfig()
const job = config.jobs.find((item) => String(item.id || '').trim() === String(jobId || '').trim()) const job = config.jobs.find((item) => String(item.id || '').trim() === String(jobId || '').trim())
@@ -72,7 +72,7 @@ export async function runScheduledJobNow(jobId) {
return result return result
} }
function scheduleJob(job, delayMs) { function scheduleJob(job: JsonObject, delayMs: number) {
const jobId = String(job.id || '').trim() const jobId = String(job.id || '').trim()
if (!jobId) { if (!jobId) {
return return
@@ -97,7 +97,7 @@ function scheduleJob(job, delayMs) {
timers.set(jobId, timer) timers.set(jobId, timer)
} }
async function runJob(job, { manual = false } = {}) { async function runJob(job: JsonObject, { manual = false }: { manual?: boolean } = {}) {
const jobId = String(job.id || '').trim() const jobId = String(job.id || '').trim()
const startedAt = new Date().toISOString() const startedAt = new Date().toISOString()
@@ -160,7 +160,7 @@ async function runJob(job, { manual = false } = {}) {
} }
} }
function dispatchJob(job) { function dispatchJob(job: JsonObject) {
if (job.type === 'cloudtentacles_health') { if (job.type === 'cloudtentacles_health') {
return runCloudtentaclesHealthJob(job) return runCloudtentaclesHealthJob(job)
} }
@@ -168,7 +168,7 @@ function dispatchJob(job) {
throw new Error(`不支持的定时任务类型:${job.type}`) throw new Error(`不支持的定时任务类型:${job.type}`)
} }
function updateJobState(jobId, patch) { function updateJobState(jobId: string, patch: JsonObject) {
const current = jobStates.get(jobId) || { const current = jobStates.get(jobId) || {
id: jobId, id: jobId,
enabled: false, enabled: false,
+10
View File
@@ -685,6 +685,16 @@
- `npm run typecheck` - `npm run typecheck`
- `npm run build` - `npm run build`
- `npm test` 共 139 个用例通过 - `npm test` 共 139 个用例通过
168. Scheduler 定时任务模块迁移到 `.ts`
- `src/services/scheduler/config-service.ts`
- `src/services/scheduler/scheduler-service.ts`
- `src/services/scheduler/cloudtentacles-health-job.ts`
169. 定时任务配置归一化、运行态缓存、立即执行、重载调度、Cloudtentacles 余额健康检查与告警已进入 TS 编译链路;job 配置、timer map、runtime state、健康检查 payload 补齐类型
170. Docker 内验证通过:
- `src/services/admin/platform-config/*.test.js` 共 37 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
## 下一步建议 ## 下一步建议