Quellcode durchsuchen

feat(syncing-server): send user based metrics to cloudwatch

Karol Sójko vor 1 Jahr
Ursprung
Commit
0c3bc0cae6

+ 32 - 0
packages/syncing-server/bin/statistics.ts

@@ -57,6 +57,38 @@ const sendStatistics = async (
       )
     }
   }
+
+  const userMetricsToProcess = [Metric.NAMES.ItemOperation, Metric.NAMES.ContentSizeUtilized]
+  for (const metricToProcess of userMetricsToProcess) {
+    for (let i = 0; i <= minutesToProcess; i++) {
+      const dateNMinutesAgo = timer.getUTCDateNMinutesAgo(minutesToProcess - i)
+      const timestamp = timer.convertDateToMicroseconds(dateNMinutesAgo)
+
+      const statistics = await metricsStore.getUserBasedStatistics(metricToProcess, timestamp)
+
+      if (statistics.sampleCount === 0) {
+        continue
+      }
+
+      await cloudwatchClient.send(
+        new PutMetricDataCommand({
+          Namespace: 'SyncingServer',
+          MetricData: [
+            {
+              MetricName: metricToProcess,
+              Timestamp: dateNMinutesAgo,
+              StatisticValues: {
+                Maximum: statistics.max,
+                Minimum: statistics.min,
+                SampleCount: statistics.sampleCount,
+                Sum: statistics.sum,
+              },
+            },
+          ],
+        }),
+      )
+    }
+  }
 }
 
 const container = new ContainerConfigLoader('worker')

+ 9 - 0
packages/syncing-server/src/Domain/Metrics/MetricsStoreInterface.ts

@@ -2,6 +2,15 @@ import { Metric } from './Metric'
 
 export interface MetricsStoreInterface {
   storeUserBasedMetric(metric: Metric, value: number, userUuid: string): Promise<void>
+  getUserBasedStatistics(
+    name: string,
+    timestamp: number,
+  ): Promise<{
+    sum: number
+    max: number
+    min: number
+    sampleCount: number
+  }>
   storeMetric(metric: Metric): Promise<void>
   getStatistics(
     name: string,

+ 12 - 0
packages/syncing-server/src/Infra/Dummy/DummyMetricStore.ts

@@ -2,6 +2,18 @@ import { MetricsStoreInterface } from '../../Domain/Metrics/MetricsStoreInterfac
 import { Metric } from '../../Domain/Metrics/Metric'
 
 export class DummyMetricStore implements MetricsStoreInterface {
+  async getUserBasedStatistics(
+    _name: string,
+    _timestamp: number,
+  ): Promise<{ sum: number; max: number; min: number; sampleCount: number }> {
+    return {
+      sum: 0,
+      max: 0,
+      min: 0,
+      sampleCount: 0,
+    }
+  }
+
   async storeUserBasedMetric(_metric: Metric, _value: number, _userUuid: string): Promise<void> {
     // do nothing
   }

+ 45 - 0
packages/syncing-server/src/Infra/Redis/RedisMetricStore.ts

@@ -29,6 +29,51 @@ export class RedisMetricStore implements MetricsStoreInterface {
     await pipeline.exec()
   }
 
+  async getUserBasedStatistics(
+    name: string,
+    timestamp: number,
+  ): Promise<{ sum: number; max: number; min: number; sampleCount: number }> {
+    const date = this.timer.convertMicrosecondsToDate(timestamp)
+    const dateToTheMinuteString = this.timer.convertDateToFormattedString(date, 'YYYY-MM-DD HH:mm')
+
+    const userMetricsKeys = await this.redisClient.keys(
+      `${this.METRIC_PER_USER_PREFIX}:*:${name}:${dateToTheMinuteString}`,
+    )
+
+    let sum = 0
+    let max = 0
+    let min = 0
+    let sampleCount = 0
+
+    const values = await this.redisClient.mget(userMetricsKeys)
+
+    for (const value of values) {
+      if (!value) {
+        continue
+      }
+
+      const valueAsNumber = Number(value)
+
+      sum += valueAsNumber
+      sampleCount++
+
+      if (valueAsNumber > max) {
+        max = valueAsNumber
+      }
+
+      if (valueAsNumber < min) {
+        min = valueAsNumber
+      }
+    }
+
+    return {
+      sum,
+      max,
+      min,
+      sampleCount,
+    }
+  }
+
   async getStatistics(
     name: string,
     from: number,