后端迁移定时任务服务
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { PROJECT_ROOT } from '../../config/runtime.js'
|
||||
|
||||
const SCHEDULED_JOBS_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'scheduled-jobs.json')
|
||||
const CLOUDTENTACLES_HEALTH_JOB_ID = 'cloudtentacles-health'
|
||||
|
||||
type JsonObject = Record<string, any>
|
||||
|
||||
export function getScheduledJobsFilePath() {
|
||||
return SCHEDULED_JOBS_FILE_PATH
|
||||
}
|
||||
|
||||
export function getScheduledJobsConfig() {
|
||||
return loadScheduledJobsConfigFromFile()
|
||||
}
|
||||
|
||||
export function saveScheduledJobsConfig(rawValue: unknown) {
|
||||
const normalized = normalizeScheduledJobsConfig(rawValue)
|
||||
fs.mkdirSync(path.dirname(SCHEDULED_JOBS_FILE_PATH), { recursive: true })
|
||||
fs.writeFileSync(SCHEDULED_JOBS_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function getCloudtentaclesHealthJob(config: JsonObject = getScheduledJobsConfig()) {
|
||||
return (Array.isArray(config.jobs) ? config.jobs : [])
|
||||
.find((item) => String(item.id || '').trim() === CLOUDTENTACLES_HEALTH_JOB_ID)
|
||||
|| createDefaultCloudtentaclesHealthJob()
|
||||
}
|
||||
|
||||
function loadScheduledJobsConfigFromFile() {
|
||||
if (!fs.existsSync(SCHEDULED_JOBS_FILE_PATH)) {
|
||||
return createDefaultScheduledJobsConfig()
|
||||
}
|
||||
|
||||
try {
|
||||
const rawText = fs.readFileSync(SCHEDULED_JOBS_FILE_PATH, 'utf8')
|
||||
return normalizeScheduledJobsConfig(JSON.parse(rawText))
|
||||
} catch {
|
||||
return createDefaultScheduledJobsConfig()
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeScheduledJobsConfig(rawValue: unknown) {
|
||||
const source = isPlainObject(rawValue) ? rawValue : {}
|
||||
const rawJobs = Array.isArray(source.jobs) ? source.jobs : []
|
||||
const jobs = rawJobs.map((item) => normalizeScheduledJob(item)).filter(Boolean)
|
||||
const hasCloudtentaclesHealth = jobs.some((item) => item.id === CLOUDTENTACLES_HEALTH_JOB_ID)
|
||||
|
||||
if (!hasCloudtentaclesHealth) {
|
||||
jobs.push(createDefaultCloudtentaclesHealthJob())
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: typeof source.enabled === 'boolean' ? source.enabled : true,
|
||||
jobs,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeScheduledJob(rawValue: unknown) {
|
||||
if (!isPlainObject(rawValue)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const type = String(rawValue.type || '').trim()
|
||||
if (type !== 'cloudtentacles_health') {
|
||||
return null
|
||||
}
|
||||
|
||||
return normalizeCloudtentaclesHealthJob(rawValue)
|
||||
}
|
||||
|
||||
function normalizeCloudtentaclesHealthJob(rawValue: JsonObject) {
|
||||
const config = isPlainObject(rawValue.config) ? rawValue.config : {}
|
||||
|
||||
return {
|
||||
id: CLOUDTENTACLES_HEALTH_JOB_ID,
|
||||
type: 'cloudtentacles_health',
|
||||
enabled: rawValue.enabled === true,
|
||||
intervalSeconds: normalizeRangeInteger(rawValue.intervalSeconds, 300, 60, 86400),
|
||||
cooldownSeconds: normalizeRangeInteger(rawValue.cooldownSeconds, 1800, 60, 86400),
|
||||
config: {
|
||||
assetThreshold: normalizeRangeInteger(config.assetThreshold, 500, 0, 999999),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function createDefaultScheduledJobsConfig() {
|
||||
return {
|
||||
enabled: true,
|
||||
jobs: [
|
||||
createDefaultCloudtentaclesHealthJob(),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
function createDefaultCloudtentaclesHealthJob() {
|
||||
return {
|
||||
id: CLOUDTENTACLES_HEALTH_JOB_ID,
|
||||
type: 'cloudtentacles_health',
|
||||
enabled: false,
|
||||
intervalSeconds: 300,
|
||||
cooldownSeconds: 1800,
|
||||
config: {
|
||||
assetThreshold: 500,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeRangeInteger(value: unknown, fallback: number, min: number, max: number) {
|
||||
const parsed = Number(value)
|
||||
if (!Number.isInteger(parsed)) {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return Math.min(max, Math.max(min, parsed))
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is JsonObject {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
Reference in New Issue
Block a user