Просмотр исходного кода

messageRecordService增加耗时统计

guoziyun 1 месяц назад
Родитель
Сommit
ea602a1496

+ 1 - 0
oms/OPTIMIZATION_TRACKER.md

@@ -138,6 +138,7 @@
   - 前端首屏加载改为优先请求 `summary`,减少首屏多接口并发重查询。
   - `api/message-records` 列表查询在无筛选场景改为 `estimatedDocumentCount`(替代全量 `countDocuments`),并增加排序白名单与 `lean()` 返回,缓解千万级数据下列表超时。
   - 修复 `summary` 慢查询:将统计去重从 `$addToSet(uid)` 改为分层聚合去重计数(避免大数组内存压力),并为 `summary` 增加默认近7天时间窗与前端同参请求去重。
+  - 新增统计接口分层耗时日志:`summary` 子查询耗时(overall/daily-trends/by-strategy)与核心聚合耗时(statistics-by-group/daily-trends/multi-dimensional)及结果规模。
 - 下一步:
   - 增加缓存失效策略与命中率监控(Phase 1)。
   - 补充 summary 与各维度接口的基准压测数据(Phase 1)。

+ 78 - 6
oms/dist/src/services/messageRecordService.js

@@ -4,6 +4,23 @@ exports.MessageRecordService = void 0;
 const messageRecordModel_1 = require("../models/messageRecordModel");
 const clients_1 = require("./clients");
 class MessageRecordService {
+    logPerf(endpoint, stage, durationMs, extra = {}) {
+        console.log(`[MessageStatsPerf] ${endpoint}:${stage}`, JSON.stringify({
+            endpoint,
+            stage,
+            durationMs,
+            ...extra,
+        }));
+    }
+    resolveResultRows(result) {
+        if (Array.isArray(result)) {
+            return result.length;
+        }
+        if (result === null || result === undefined) {
+            return 0;
+        }
+        return 1;
+    }
     /**
      * 创建一条新的消息推送记录
      * @param recordData 消息记录数据
@@ -171,11 +188,39 @@ class MessageRecordService {
      * 用于首屏减少多次并行重查询。
      */
     async getStatisticsSummary(startDate, endDate, strategyName, page = MessageRecordService.DEFAULT_STATS_PAGE, limit = MessageRecordService.DEFAULT_STATS_LIMIT) {
+        const summaryStartedAt = Date.now();
         const [overall, dailyTrends, strategyStats] = await Promise.all([
-            this.getOverallStatistics(startDate, endDate, strategyName),
-            this.getDailySentTrends(startDate, endDate, strategyName),
-            this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit),
+            (async () => {
+                const startedAt = Date.now();
+                const result = await this.getOverallStatistics(startDate, endDate, strategyName);
+                this.logPerf("summary", "overall", Date.now() - startedAt, {
+                    resultRows: this.resolveResultRows(result),
+                });
+                return result;
+            })(),
+            (async () => {
+                const startedAt = Date.now();
+                const result = await this.getDailySentTrends(startDate, endDate, strategyName);
+                this.logPerf("summary", "daily-trends", Date.now() - startedAt, {
+                    resultRows: this.resolveResultRows(result),
+                });
+                return result;
+            })(),
+            (async () => {
+                const startedAt = Date.now();
+                const result = await this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit);
+                this.logPerf("summary", "by-strategy", Date.now() - startedAt, {
+                    resultRows: this.resolveResultRows(result),
+                    page,
+                    limit,
+                });
+                return result;
+            })(),
         ]);
+        this.logPerf("summary", "total", Date.now() - summaryStartedAt, {
+            dailyTrendRows: this.resolveResultRows(dailyTrends),
+            strategyRows: this.resolveResultRows(strategyStats),
+        });
         return {
             overall,
             dailyTrends,
@@ -215,6 +260,7 @@ class MessageRecordService {
      */
     async getMultiDimensionalStatistics(filters) {
         try {
+            const startedAt = Date.now();
             const pipeline = [];
             // 构建匹配阶段
             const matchStage = this.buildMatchConditions(filters.startDate, filters.endDate, filters.strategyName);
@@ -266,7 +312,16 @@ class MessageRecordService {
             pipeline.push({
                 $sort: { date: 1, templateName: 1, cc: 1, image: 1 },
             });
-            return await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
+            const result = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
+            this.logPerf("multi-dimensional", "aggregate", Date.now() - startedAt, {
+                resultRows: this.resolveResultRows(result),
+                hasDateRange: Boolean(filters.startDate || filters.endDate),
+                hasStrategy: Boolean(filters.strategyName),
+                hasTemplate: Boolean(filters.templateName),
+                hasCc: Boolean(filters.cc),
+                hasImage: Boolean(filters.image),
+            });
+            return result;
         }
         catch (error) {
             console.error("Error fetching multi-dimensional statistics:", error);
@@ -416,6 +471,7 @@ class MessageRecordService {
      */
     async getStatisticsByGroup(matchConditions, groupFields = [], sortOrder = { _id: 1 }, page = MessageRecordService.DEFAULT_STATS_PAGE, limit = MessageRecordService.DEFAULT_STATS_LIMIT) {
         try {
+            const startedAt = Date.now();
             const pipeline = [];
             // 添加匹配阶段
             if (Object.keys(matchConditions).length > 0) {
@@ -479,7 +535,15 @@ class MessageRecordService {
                 pipeline.push({ $limit: safeLimit });
             }
             const results = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
-            return groupFields.length === 0 ? results[0] : results;
+            const output = groupFields.length === 0 ? results[0] : results;
+            this.logPerf("statistics-by-group", "aggregate", Date.now() - startedAt, {
+                groupFields: groupFields.join(",") || "overall",
+                matchKeyCount: Object.keys(matchConditions || {}).length,
+                resultRows: this.resolveResultRows(output),
+                page,
+                limit,
+            });
+            return output;
         }
         catch (error) {
             console.error("Error fetching statistics by group:", error);
@@ -491,6 +555,7 @@ class MessageRecordService {
      */
     async getDailyTrendsByDimensions(startDate, endDate, strategyName, extraConditions = []) {
         try {
+            const startedAt = Date.now();
             const pipeline = [];
             // 构建匹配条件
             let matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
@@ -572,7 +637,14 @@ class MessageRecordService {
             pipeline.push({
                 $sort: { date: -1 },
             });
-            return await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
+            const result = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
+            this.logPerf("daily-trends", "aggregate", Date.now() - startedAt, {
+                hasDateRange: Boolean(startDate || endDate),
+                hasStrategy: Boolean(strategyName),
+                extraConditionCount: extraConditions.length,
+                resultRows: this.resolveResultRows(result),
+            });
+            return result;
         }
         catch (error) {
             console.error("Error fetching daily trends:", error);

+ 85 - 6
oms/src/services/messageRecordService.ts

@@ -25,6 +25,28 @@ export class MessageRecordService {
   public static readonly MAX_STATS_LIMIT = 200;
   private static readonly STATS_CACHE_TTL_SECONDS = 300;
 
+  private logPerf(endpoint: string, stage: string, durationMs: number, extra: Record<string, unknown> = {}) {
+    console.log(
+      `[MessageStatsPerf] ${endpoint}:${stage}`,
+      JSON.stringify({
+        endpoint,
+        stage,
+        durationMs,
+        ...extra,
+      })
+    );
+  }
+
+  private resolveResultRows(result: unknown): number {
+    if (Array.isArray(result)) {
+      return result.length;
+    }
+    if (result === null || result === undefined) {
+      return 0;
+    }
+    return 1;
+  }
+
   /**
    * 创建一条新的消息推送记录
    * @param recordData 消息记录数据
@@ -251,12 +273,42 @@ export class MessageRecordService {
     page: number = MessageRecordService.DEFAULT_STATS_PAGE,
     limit: number = MessageRecordService.DEFAULT_STATS_LIMIT
   ) {
+    const summaryStartedAt = Date.now();
+
     const [overall, dailyTrends, strategyStats] = await Promise.all([
-      this.getOverallStatistics(startDate, endDate, strategyName),
-      this.getDailySentTrends(startDate, endDate, strategyName),
-      this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit),
+      (async () => {
+        const startedAt = Date.now();
+        const result = await this.getOverallStatistics(startDate, endDate, strategyName);
+        this.logPerf("summary", "overall", Date.now() - startedAt, {
+          resultRows: this.resolveResultRows(result),
+        });
+        return result;
+      })(),
+      (async () => {
+        const startedAt = Date.now();
+        const result = await this.getDailySentTrends(startDate, endDate, strategyName);
+        this.logPerf("summary", "daily-trends", Date.now() - startedAt, {
+          resultRows: this.resolveResultRows(result),
+        });
+        return result;
+      })(),
+      (async () => {
+        const startedAt = Date.now();
+        const result = await this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit);
+        this.logPerf("summary", "by-strategy", Date.now() - startedAt, {
+          resultRows: this.resolveResultRows(result),
+          page,
+          limit,
+        });
+        return result;
+      })(),
     ]);
 
+    this.logPerf("summary", "total", Date.now() - summaryStartedAt, {
+      dailyTrendRows: this.resolveResultRows(dailyTrends),
+      strategyRows: this.resolveResultRows(strategyStats),
+    });
+
     return {
       overall,
       dailyTrends,
@@ -301,6 +353,7 @@ export class MessageRecordService {
    */
   public async getMultiDimensionalStatistics(filters: { startDate?: Date; endDate?: Date; templateName?: string; strategyName?: string; cc?: string; image?: string }) {
     try {
+      const startedAt = Date.now();
       const pipeline: any[] = [];
 
       // 构建匹配阶段
@@ -357,7 +410,16 @@ export class MessageRecordService {
         $sort: { date: 1, templateName: 1, cc: 1, image: 1 },
       });
 
-      return await MessageRecord.aggregate(pipeline).allowDiskUse(true);
+      const result = await MessageRecord.aggregate(pipeline).allowDiskUse(true);
+      this.logPerf("multi-dimensional", "aggregate", Date.now() - startedAt, {
+        resultRows: this.resolveResultRows(result),
+        hasDateRange: Boolean(filters.startDate || filters.endDate),
+        hasStrategy: Boolean(filters.strategyName),
+        hasTemplate: Boolean(filters.templateName),
+        hasCc: Boolean(filters.cc),
+        hasImage: Boolean(filters.image),
+      });
+      return result;
     } catch (error) {
       console.error("Error fetching multi-dimensional statistics:", error);
       return [];
@@ -532,6 +594,7 @@ export class MessageRecordService {
     limit: number = MessageRecordService.DEFAULT_STATS_LIMIT
   ) {
     try {
+      const startedAt = Date.now();
       const pipeline: any[] = [];
 
       // 添加匹配阶段
@@ -609,7 +672,15 @@ export class MessageRecordService {
       }
 
       const results = await MessageRecord.aggregate(pipeline).allowDiskUse(true);
-      return groupFields.length === 0 ? results[0] : results;
+      const output = groupFields.length === 0 ? results[0] : results;
+      this.logPerf("statistics-by-group", "aggregate", Date.now() - startedAt, {
+        groupFields: groupFields.join(",") || "overall",
+        matchKeyCount: Object.keys(matchConditions || {}).length,
+        resultRows: this.resolveResultRows(output),
+        page,
+        limit,
+      });
+      return output;
     } catch (error) {
       console.error("Error fetching statistics by group:", error);
       return groupFields.length === 0 ? null : [];
@@ -621,6 +692,7 @@ export class MessageRecordService {
    */
   private async getDailyTrendsByDimensions(startDate?: Date, endDate?: Date, strategyName?: string, extraConditions: any[] = []) {
     try {
+      const startedAt = Date.now();
       const pipeline: any[] = [];
 
       // 构建匹配条件
@@ -712,7 +784,14 @@ export class MessageRecordService {
         $sort: { date: -1 },
       });
 
-      return await MessageRecord.aggregate(pipeline).allowDiskUse(true);
+      const result = await MessageRecord.aggregate(pipeline).allowDiskUse(true);
+      this.logPerf("daily-trends", "aggregate", Date.now() - startedAt, {
+        hasDateRange: Boolean(startDate || endDate),
+        hasStrategy: Boolean(strategyName),
+        extraConditionCount: extraConditions.length,
+        resultRows: this.resolveResultRows(result),
+      });
+      return result;
     } catch (error) {
       console.error("Error fetching daily trends:", error);
       return [];