guoziyun 7 mesi fa
parent
commit
ce0328c943
2 ha cambiato i file con 76 aggiunte e 34 eliminazioni
  1. 37 17
      oms/dist/services/cron-jobs/done-rate.js
  2. 39 17
      oms/services/cron-jobs/done-rate.ts

+ 37 - 17
oms/dist/services/cron-jobs/done-rate.js

@@ -7,21 +7,37 @@ const doneRateService_1 = __importDefault(require("../../src/services/doneRateSe
 const clients_1 = require("../../src/services/clients");
 const mongoose_1 = __importDefault(require("mongoose")); // 导入 mongoose 和 Connection 用于处理远程连接
 const totalDoneRateModel_1 = __importDefault(require("../../src/models/totalDoneRateModel")); // 导入 TotalDoneRate 模型 (已包含 totalTipCount)
-const doneRateModel_1 = __importDefault(require("../../src/models/doneRateModel")); // 【新增】导入 DoneRateModel 用于聚合历史数据
+const doneRateModel_1 = __importDefault(require("../../src/models/doneRateModel")); // 导入 DoneRateModel 用于聚合历史数据
 // ClickHouse 表名
 const CLICKHOUSE_EVENTS_TABLE = "events"; // 确保与 ClickHouseService 中的表名一致
 /**
- * 每日统计昨天的作品完成率。
- * 统计逻辑从 ClickHouse 中提取数据,得到每个作品的完成情况、道具使用情况,并更新到 DoneRate 模型。
- * 随后,根据这些日统计数据,通过聚合 TotalDoneRate 表 (包括 totalTipCount)。
+ * 每日统计作品完成率。
+ * 如果提供了 dateStr (YYYY-MM-DD 或 YYYYMMDD),则统计该日的数据;否则,默认统计昨天的数据。
+ * 统计逻辑从 ClickHouse 中提取数据,得到每个作品的完成情况、道具使用情况,并更新到 doneRateModel。
+ * 随后,通过聚合这些日统计数据,更新本地的 totalDoneRate 表 (包括 totalTipCount)。
+ * @param dateStr 可选参数,指定要统计的日期 (例如: '2023-10-25')。
  * @returns Promise<string> - 返回统计结果的摘要信息。
  */
-async function run() {
-    console.log("[DoneRate Cron] Starting daily done-rate calculation for yesterday...");
-    // 获取昨天和今天的日期
-    const yesterday = (0, dayjs_1.default)().subtract(1, "day");
+async function run(dateStr) {
+    console.log("[DoneRate Cron] Starting done-rate calculation...");
+    // --- 确定目标日期 ---
+    let targetDay;
+    if (dateStr) {
+        targetDay = (0, dayjs_1.default)(dateStr).startOf("day");
+        if (!targetDay.isValid()) {
+            throw new Error(`Invalid date format provided: ${dateStr}`);
+        }
+        console.log(`[DoneRate Cron] Running for specified date: ${targetDay.format("YYYY-MM-DD")}`);
+    }
+    else {
+        // 默认执行逻辑:统计昨天
+        targetDay = (0, dayjs_1.default)().subtract(1, "day").startOf("day");
+        console.log(`[DoneRate Cron] Running for default date (yesterday): ${targetDay.format("YYYY-MM-DD")}`);
+    }
+    // 使用 targetDay 变量名以兼容后续代码
+    const yesterday = targetDay;
     const yesterdayYYYYMMDD = yesterday.format("YYYYMMDD");
-    const yesterdayStart = yesterday.startOf("day").toDate();
+    const yesterdayStart = yesterday.toDate();
     const yesterdayEnd = yesterday.endOf("day").toDate();
     // 格式化日期字符串,使其符合 ClickHouse 的 toDateTime() 函数要求
     const yesterdayStartString = (0, dayjs_1.default)(yesterdayStart).format("YYYY-MM-DD HH:mm:ss");
@@ -29,8 +45,7 @@ async function run() {
     console.log(`[DoneRate Cron] Processing data for date: ${yesterdayYYYYMMDD}`);
     try {
         // --- 1. 从 ClickHouse 中提取数据 (Start, Done, Tip Counts) ---
-        // (此处是 ClickHouse 可能发生超时的地方)
-        // 1.1 查询昨天每个作品的独立开始用户数
+        // 1.1 查询目标日期每个作品的独立开始用户数
         const startCountsQuery = `
       SELECT
           res,
@@ -53,7 +68,7 @@ async function run() {
             }
         });
         console.log(`[DoneRate Cron] Retrieved ${startResults.length} unique start counts from ClickHouse.`);
-        // 1.2 查询昨天每个作品的独立完成用户数
+        // 1.2 查询目标日期每个作品的独立完成用户数
         const doneCountsQuery = `
       SELECT
           res,
@@ -76,7 +91,7 @@ async function run() {
             }
         });
         console.log(`[DoneRate Cron] Retrieved ${doneResults.length} unique done counts from ClickHouse.`);
-        // 1.3 查询昨天每个作品的使用道具数
+        // 1.3 查询目标日期每个作品的使用道具数
         const tipCountsQuery = `
       SELECT
           res,
@@ -121,11 +136,10 @@ async function run() {
         const totalProcessedArtworks = createdRecordsCount + updatedRecordsCount;
         console.log(`[DoneRate Cron] DoneRate model (Daily) update completed. Total artworks processed: ${totalProcessedArtworks}. Created: ${createdRecordsCount}, Updated: ${updatedRecordsCount}.`);
         // --- 3. 重新聚合并更新本地的 TotalDoneRate 表 (累计记录) ---
-        // 🚨 修正:原先的 Read-Modify-Write 逻辑被替换为更健壮的 MongoDB 聚合。
         // 通过聚合 DoneRate 日记录来计算最新的累计总数,确保幂等性。
-        // 3.1 聚合所有历史 DoneRate 记录直到昨天
+        // 3.1 聚合所有历史 DoneRate 记录直到昨天 (即 targetDay)
         const aggregationPipeline = [
-            // 匹配所有小于或等于昨天的日期记录
+            // 匹配所有小于或等于目标日期的记录
             { $match: { date: { $lte: yesterdayYYYYMMDD } } },
             {
                 $group: {
@@ -180,9 +194,15 @@ async function run() {
     catch (error) {
         console.error(`[DoneRate Cron] Error during done-rate calculation for ${yesterdayYYYYMMDD}:`, error);
         // 重新抛出错误,以便 cron 调度器能够捕获并记录失败
-        throw new Error(`Failed to calculate daily done-rates: ${error instanceof Error ? error.message : String(error)}`);
+        throw new Error(`Failed to calculate daily done-rates for ${yesterdayYYYYMMDD}: ${error instanceof Error ? error.message : String(error)}`);
     }
     finally {
     }
 }
+if (require.main === module) {
+    run().catch((err) => {
+        console.error(err);
+        process.exit(1);
+    });
+}
 module.exports = { run };

+ 39 - 17
oms/services/cron-jobs/done-rate.ts

@@ -3,7 +3,7 @@ import doneRateService from "../../src/services/doneRateService"; // 导入 Done
 import { clickhouseService } from "../../src/services/clients";
 import mongoose, { Connection } from "mongoose"; // 导入 mongoose 和 Connection 用于处理远程连接
 import TotalDoneRate from "../../src/models/totalDoneRateModel"; // 导入 TotalDoneRate 模型 (已包含 totalTipCount)
-import DoneRateModel from "../../src/models/doneRateModel"; // 【新增】导入 DoneRateModel 用于聚合历史数据
+import DoneRateModel from "../../src/models/doneRateModel"; // 导入 DoneRateModel 用于聚合历史数据
 
 // ClickHouse 表名
 const CLICKHOUSE_EVENTS_TABLE = "events"; // 确保与 ClickHouseService 中的表名一致
@@ -33,18 +33,35 @@ interface ClickHouseTipCountResult {
 }
 
 /**
- * 每日统计昨天的作品完成率。
- * 统计逻辑从 ClickHouse 中提取数据,得到每个作品的完成情况、道具使用情况,并更新到 DoneRate 模型。
- * 随后,根据这些日统计数据,通过聚合 TotalDoneRate 表 (包括 totalTipCount)。
+ * 每日统计作品完成率。
+ * 如果提供了 dateStr (YYYY-MM-DD 或 YYYYMMDD),则统计该日的数据;否则,默认统计昨天的数据。
+ * 统计逻辑从 ClickHouse 中提取数据,得到每个作品的完成情况、道具使用情况,并更新到 doneRateModel。
+ * 随后,通过聚合这些日统计数据,更新本地的 totalDoneRate 表 (包括 totalTipCount)。
+ * @param dateStr 可选参数,指定要统计的日期 (例如: '2023-10-25')。
  * @returns Promise<string> - 返回统计结果的摘要信息。
  */
-async function run(): Promise<string> {
-  console.log("[DoneRate Cron] Starting daily done-rate calculation for yesterday...");
+async function run(dateStr?: string | dayjs.Dayjs): Promise<string> {
+  console.log("[DoneRate Cron] Starting done-rate calculation...");
 
-  // 获取昨天和今天的日期
-  const yesterday = dayjs().subtract(1, "day");
+  // --- 确定目标日期 ---
+  let targetDay: dayjs.Dayjs;
+
+  if (dateStr) {
+    targetDay = dayjs(dateStr).startOf("day");
+    if (!targetDay.isValid()) {
+      throw new Error(`Invalid date format provided: ${dateStr}`);
+    }
+    console.log(`[DoneRate Cron] Running for specified date: ${targetDay.format("YYYY-MM-DD")}`);
+  } else {
+    // 默认执行逻辑:统计昨天
+    targetDay = dayjs().subtract(1, "day").startOf("day");
+    console.log(`[DoneRate Cron] Running for default date (yesterday): ${targetDay.format("YYYY-MM-DD")}`);
+  }
+
+  // 使用 targetDay 变量名以兼容后续代码
+  const yesterday = targetDay;
   const yesterdayYYYYMMDD = yesterday.format("YYYYMMDD");
-  const yesterdayStart = yesterday.startOf("day").toDate();
+  const yesterdayStart = yesterday.toDate();
   const yesterdayEnd = yesterday.endOf("day").toDate();
 
   // 格式化日期字符串,使其符合 ClickHouse 的 toDateTime() 函数要求
@@ -55,9 +72,8 @@ async function run(): Promise<string> {
 
   try {
     // --- 1. 从 ClickHouse 中提取数据 (Start, Done, Tip Counts) ---
-    // (此处是 ClickHouse 可能发生超时的地方)
 
-    // 1.1 查询昨天每个作品的独立开始用户数
+    // 1.1 查询目标日期每个作品的独立开始用户数
     const startCountsQuery = `
       SELECT
           res,
@@ -80,7 +96,7 @@ async function run(): Promise<string> {
     });
     console.log(`[DoneRate Cron] Retrieved ${startResults.length} unique start counts from ClickHouse.`);
 
-    // 1.2 查询昨天每个作品的独立完成用户数
+    // 1.2 查询目标日期每个作品的独立完成用户数
     const doneCountsQuery = `
       SELECT
           res,
@@ -103,7 +119,7 @@ async function run(): Promise<string> {
     });
     console.log(`[DoneRate Cron] Retrieved ${doneResults.length} unique done counts from ClickHouse.`);
 
-    // 1.3 查询昨天每个作品的使用道具数
+    // 1.3 查询目标日期每个作品的使用道具数
     const tipCountsQuery = `
       SELECT
           res,
@@ -153,12 +169,11 @@ async function run(): Promise<string> {
     console.log(`[DoneRate Cron] DoneRate model (Daily) update completed. Total artworks processed: ${totalProcessedArtworks}. Created: ${createdRecordsCount}, Updated: ${updatedRecordsCount}.`);
 
     // --- 3. 重新聚合并更新本地的 TotalDoneRate 表 (累计记录) ---
-    // 🚨 修正:原先的 Read-Modify-Write 逻辑被替换为更健壮的 MongoDB 聚合。
     // 通过聚合 DoneRate 日记录来计算最新的累计总数,确保幂等性。
 
-    // 3.1 聚合所有历史 DoneRate 记录直到昨天
+    // 3.1 聚合所有历史 DoneRate 记录直到昨天 (即 targetDay)
     const aggregationPipeline = [
-      // 匹配所有小于或等于昨天的日期记录
+      // 匹配所有小于或等于目标日期的记录
       { $match: { date: { $lte: yesterdayYYYYMMDD } } },
       {
         $group: {
@@ -224,9 +239,16 @@ async function run(): Promise<string> {
   } catch (error) {
     console.error(`[DoneRate Cron] Error during done-rate calculation for ${yesterdayYYYYMMDD}:`, error);
     // 重新抛出错误,以便 cron 调度器能够捕获并记录失败
-    throw new Error(`Failed to calculate daily done-rates: ${error instanceof Error ? error.message : String(error)}`);
+    throw new Error(`Failed to calculate daily done-rates for ${yesterdayYYYYMMDD}: ${error instanceof Error ? error.message : String(error)}`);
   } finally {
   }
 }
 
 export = { run }; // 导出 run 函数以供 cron-jobs/index.ts 使用
+
+if (require.main === module) {
+  run().catch((err) => {
+    console.error(err);
+    process.exit(1);
+  });
+}