后端迁移定时任务服务
This commit is contained in:
+3
-3
@@ -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()
|
||||||
+9
-9
@@ -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]'
|
||||||
}
|
}
|
||||||
+10
-10
@@ -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,
|
||||||
@@ -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 个用例通过
|
||||||
|
|
||||||
## 下一步建议
|
## 下一步建议
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user