import { Provide, Inject } from '@midwayjs/core';
|
import { BaseService } from '@cool-midway/core';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { Repository, In } from 'typeorm';
|
import { ReportJoblogEntity } from '../entity/joblog';
|
import { ExecutorSiteDeptDaily } from './ExecutorSiteDeptDaily'
|
import { ExecutorVehicleDaily } from './ExecutorVehicleDaily'
|
|
/**
|
* 定时任务-汇总站点/各个单位的各类垃圾汇总数据
|
* 总入口,创建和调度任务,具体执行调用TaskSiteService 和 TaskDepartmentService
|
*/
|
|
|
@Provide()
|
export class ReportTaskService extends BaseService {
|
@InjectEntityModel(ReportJoblogEntity)
|
reportJoblogEntity: Repository<ReportJoblogEntity>;
|
|
@Inject()
|
executorSiteDeptDaily: ExecutorSiteDeptDaily;
|
|
@Inject()
|
executorVehicleDaily: ExecutorVehicleDaily;
|
|
|
|
/**
|
* 外部定时任务(Crontab)每小时调用的总入口
|
* 建议表达式: 0 5 * * * * (每小时的第5分钟执行)
|
*/
|
async clockIn() {
|
// 1. 自动看门狗:确保昨天和今天的任务实例已经在表里初始化了
|
await this.ensureJobInstancesCreated();
|
|
// 2. 两类任务同时执行
|
// 后续增加新的 task service 比如 更新 萤石云 token, 统计分拣员行为等等。
|
|
await Promise.all([
|
this.executorSiteDeptDaily.execute(),
|
this.executorVehicleDaily.execute()
|
|
]);
|
|
|
return '任务执行:ReportTaskService';
|
}
|
|
/**
|
* 检查并初始化任务实例(守护动作)
|
*/
|
private async ensureJobInstancesCreated() {
|
const now = new Date();
|
const year = now.getFullYear();
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
const day = String(now.getDate()).padStart(2, '0');
|
const yesterdayDate = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
const yYear = yesterdayDate.getFullYear();
|
const yMonth = String(yesterdayDate.getMonth() + 1).padStart(2, '0');
|
const yDay = String(yesterdayDate.getDate()).padStart(2, '0');
|
|
const todayStr = `${year}-${month}-${day}`;
|
const yesterdayStr = `${yYear}-${yMonth}-${yDay}`;
|
|
// 我们需要守护的目标日期和任务类型组合
|
const targets = [
|
{ date: yesterdayStr, type: 'SITE_DAILY', isToday: false },
|
{ date: yesterdayStr, type: 'DEPT_DAILY', isToday: false },
|
{ date: yesterdayStr, type: 'VEHICLE_DAILY', isToday: false }, // 新增
|
|
{ date: todayStr, type: 'SITE_DAILY', isToday: true },
|
{ date: todayStr, type: 'DEPT_DAILY', isToday: true },
|
{ date: todayStr, type: 'VEHICLE_DAILY', isToday: true }, // 新增
|
|
];
|
|
for (const target of targets) {
|
try {
|
// 利用 try-catch 和数据库唯一索引,防并发同时也能实现“不存在则创建”
|
const exist = await this.reportJoblogEntity.findOneBy({
|
jobName: target.type,
|
dataDate: target.date,
|
});
|
if (!exist) {
|
const job = new ReportJoblogEntity();
|
job.jobName = target.type;
|
job.dataDate = target.date;
|
job.status = 'INIT';
|
await this.reportJoblogEntity.save(job);
|
} else if (target.isToday && exist.status === 'SUCCESS') {
|
// 2. 【核心修复】如果是今天的任务,且已经是 SUCCESS 状态,强行洗回 INIT 参与本小时的重算
|
await this.reportJoblogEntity.update(exist.id, {
|
status: 'INIT'
|
});
|
}
|
} catch (err) {
|
// 并发写入时可能触发唯一索引冲突,直接忽略即可
|
}
|
}
|
}
|
|
|
}
|