]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: fix memory leak in prometheus service
authorNizamudeen A <nia@redhat.com>
Fri, 8 Aug 2025 06:42:20 +0000 (12:12 +0530)
committerNizamudeen A <nia@redhat.com>
Tue, 19 Aug 2025 05:45:14 +0000 (11:15 +0530)
Prometheus API calls in the Cluster Utilization call is subscribed in
the for loop multiple times but this is not properly unsubscribed. As we
stay in the dashboard page for longer time, it produces a significant
memory leak which eventually lags the UI. Attempting to fix it by
properly handling the subscription

Fixes: https://tracker.ceph.com/issues/72511
Signed-off-by: Nizamudeen A <nia@redhat.com>
(cherry picked from commit 26765720b972453bc69f23cd5644366bba998391)

src/pybind/mgr/dashboard/frontend/src/app/shared/api/prometheus.service.ts

index fedc7b8de0f6dad36c198fbd24924e16afae623c..8e1151da13d0d677cf1ae8ac4f73f4f1bafbb933 100644 (file)
@@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 
 import { Observable, Subscription, forkJoin, timer } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { map, switchMap } from 'rxjs/operators';
 
 import { AlertmanagerSilence } from '../models/alertmanager-silence';
 import {
@@ -141,37 +141,47 @@ export class PrometheusService {
       if (this.timerGetPrometheusDataSub) {
         this.timerGetPrometheusDataSub.unsubscribe();
       }
-      this.timerGetPrometheusDataSub = timer(0, this.timerTime).subscribe(() => {
-        selectedTime = this.updateTimeStamp(selectedTime);
-        for (const queryName in queries) {
-          if (queries.hasOwnProperty(queryName)) {
-            const query = queries[queryName];
-            this.getPrometheusData({
-              params: encodeURIComponent(query),
-              start: selectedTime['start'],
-              end: selectedTime['end'],
-              step: selectedTime['step']
-            }).subscribe((data: any) => {
-              if (data.result.length) {
-                queriesResults[queryName] = data.result[0].values;
-              } else {
-                queriesResults[queryName] = [];
-              }
-              if (
-                queriesResults[queryName] !== undefined &&
-                queriesResults[queryName] !== '' &&
-                checkNan
-              ) {
-                queriesResults[queryName].forEach((valueArray: any[]) => {
-                  if (isNaN(parseFloat(valueArray[1]))) {
-                    valueArray[1] = '0';
-                  }
-                });
+      this.timerGetPrometheusDataSub = timer(0, this.timerTime)
+        .pipe(
+          switchMap(() => {
+            selectedTime = this.updateTimeStamp(selectedTime);
+            const observables = [];
+            for (const queryName in queries) {
+              if (queries.hasOwnProperty(queryName)) {
+                const query = queries[queryName];
+                observables.push(
+                  this.getPrometheusData({
+                    params: encodeURIComponent(query),
+                    start: selectedTime['start'],
+                    end: selectedTime['end'],
+                    step: selectedTime['step']
+                  }).pipe(map((data: any) => ({ queryName, data })))
+                );
               }
-            });
-          }
-        }
-      });
+            }
+            return forkJoin(observables);
+          })
+        )
+        .subscribe((results: any) => {
+          results.forEach(({ queryName, data }: any) => {
+            if (data.result.length) {
+              queriesResults[queryName] = data.result[0].values;
+            } else {
+              queriesResults[queryName] = [];
+            }
+            if (
+              queriesResults[queryName] !== undefined &&
+              queriesResults[queryName] !== '' &&
+              checkNan
+            ) {
+              queriesResults[queryName].forEach((valueArray: any[]) => {
+                if (isNaN(parseFloat(valueArray[1]))) {
+                  valueArray[1] = '0';
+                }
+              });
+            }
+          });
+        });
     });
     return queriesResults;
   }