wangzhibo
2026-07-28 2b662657c5bc5bc45b69f475c7b2edcf8fc92f0c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { Provide, Inject } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository, In } from 'typeorm';
import { ReportJoblogEntity } from '../entity/joblog';
import { TaskServiceSite } from './taskservicesite'
import { TaskServiceDepartment } from './taskservicedepartment'
 
 
 
@Provide()
export class ExecutorSiteDeptDaily {
 
    @InjectEntityModel(ReportJoblogEntity)
    reportJoblogEntity: Repository<ReportJoblogEntity>;
 
    @Inject()
    taskServiceSite: TaskServiceSite;
 
    @Inject()
    taskServiceDepartment: TaskServiceDepartment;
 
    async execute() {
        // 捞出所有待处理任务
        const pendingSiteJobs = await this.reportJoblogEntity.find({
            where: {
                status: In(['INIT', 'FAILED']),
                jobName: In(['SITE_DAILY', 'DEPT_DAILY']),
            },
            order: {
                dataDate: 'ASC', // 先算历史,后算今天
                // 确保在同一天内,SITE_DAILY 先跑,DEPT_DAILY 后跑
                // 在 JS 数组中我们可以进一步控制排序,或者由业务逻辑严格控制依赖
            },
        });
 
        for (const job of pendingSiteJobs) {
            // 严格依赖检查:如果是部门日表任务,必须确保同天的站点日表任务已经是 SUCCESS
            if (job.jobName === 'DEPT_DAILY') {
                const siteJob = await this.reportJoblogEntity.findOneBy({
                    dataDate: job.dataDate,
                    jobName: 'SITE_DAILY',
                });
                if (!siteJob || siteJob.status !== 'SUCCESS') {
                    // 源头明细还没算好/或还在运行,部门表任务必须等待,跳过本次执行
                    continue;
                }
            }
 
            // 锁定任务状态为 RUNNING(轻量级乐观锁锁机制)
            const lockResult = await this.reportJoblogEntity.update(
                { id: job.id, status: job.status }, // 带有原始状态检查,防止被别的线程抢跑
                { status: 'RUNNING', startTime: new Date() }
            );
 
            if (lockResult.affected === 0) {
                continue; // 没抢到锁,说明别的定时器在跑它,跳过
            }
 
            // 真正开始跑数据
            try {
                let recordsProcessed = 0;
 
                if (job.jobName === 'SITE_DAILY') {
                    // 调用你写的 站点日表 提取逻辑
                    recordsProcessed = await this.taskServiceSite.aggregateDailyData(job.dataDate) || 0;
                } else if (job.jobName === 'DEPT_DAILY') {
                    // 调用你写的 部门树轰炸 提取逻辑
                    recordsProcessed = await this.taskServiceDepartment.aggregateDailyData(job.dataDate) || 0;
                }
 
                // 成功:更新状态
                await this.reportJoblogEntity.update(job.id, {
                    status: 'SUCCESS',
                    recordsProcessed: recordsProcessed,
                    endTime: new Date(),
                    errorMessage: '',
                });
 
            } catch (error) {
                // 失败:记录堆栈,等待下一小时重试
 
                var errorMessage = '';
                if (error instanceof Error) {
                    errorMessage = error.stack ?? error.message;
                }
                if (typeof error === 'string') {
                    errorMessage = error;
                }
                try {
                    errorMessage = JSON.stringify(error);
                } catch {
                    errorMessage = String(error);
                }
 
                await this.reportJoblogEntity.update(job.id, {
                    status: 'FAILED',
                    endTime: new Date(),
                    errorMessage: errorMessage,
                    failedCount: () => 'failedCount + 1',
                });
            }
        }
    }
 
}