Merge pull request #3230 from mempool/mononaut/heap-monitor
Monitor heap memory usage
This commit is contained in:
		
						commit
						07271f56d7
					
				@ -38,6 +38,8 @@ import forensicsService from './tasks/lightning/forensics.service';
 | 
			
		||||
import priceUpdater from './tasks/price-updater';
 | 
			
		||||
import chainTips from './api/chain-tips';
 | 
			
		||||
import { AxiosError } from 'axios';
 | 
			
		||||
import v8 from 'v8';
 | 
			
		||||
import { formatBytes, getBytesUnit } from './utils/format';
 | 
			
		||||
 | 
			
		||||
class Server {
 | 
			
		||||
  private wss: WebSocket.Server | undefined;
 | 
			
		||||
@ -45,6 +47,11 @@ class Server {
 | 
			
		||||
  private app: Application;
 | 
			
		||||
  private currentBackendRetryInterval = 5;
 | 
			
		||||
 | 
			
		||||
  private maxHeapSize: number = 0;
 | 
			
		||||
  private heapLogInterval: number = 60;
 | 
			
		||||
  private warnedHeapCritical: boolean = false;
 | 
			
		||||
  private lastHeapLogTime: number | null = null;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.app = express();
 | 
			
		||||
 | 
			
		||||
@ -137,6 +144,8 @@ class Server {
 | 
			
		||||
      this.runMainUpdateLoop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setInterval(() => { this.healthCheck(); }, 2500);
 | 
			
		||||
 | 
			
		||||
    if (config.BISQ.ENABLED) {
 | 
			
		||||
      bisq.startBisqService();
 | 
			
		||||
      bisq.setPriceCallbackFunction((price) => websocketHandler.setExtraInitProperties('bsq-price', price));
 | 
			
		||||
@ -255,6 +264,26 @@ class Server {
 | 
			
		||||
      channelsRoutes.initRoutes(this.app);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  healthCheck(): void {
 | 
			
		||||
    const now = Date.now();
 | 
			
		||||
    const stats = v8.getHeapStatistics();
 | 
			
		||||
    this.maxHeapSize = Math.max(stats.used_heap_size, this.maxHeapSize);
 | 
			
		||||
    const warnThreshold = 0.8 * stats.heap_size_limit;
 | 
			
		||||
 | 
			
		||||
    const byteUnits = getBytesUnit(Math.max(this.maxHeapSize, stats.heap_size_limit));
 | 
			
		||||
 | 
			
		||||
    if (!this.warnedHeapCritical && this.maxHeapSize > warnThreshold) {
 | 
			
		||||
      this.warnedHeapCritical = true;
 | 
			
		||||
      logger.warn(`Used ${(this.maxHeapSize / stats.heap_size_limit).toFixed(2)}% of heap limit (${formatBytes(this.maxHeapSize, byteUnits, true)} / ${formatBytes(stats.heap_size_limit, byteUnits)})!`);
 | 
			
		||||
    }
 | 
			
		||||
    if (this.lastHeapLogTime === null || (now - this.lastHeapLogTime) > (this.heapLogInterval * 1000)) {
 | 
			
		||||
      logger.debug(`Memory usage: ${formatBytes(this.maxHeapSize, byteUnits)} / ${formatBytes(stats.heap_size_limit, byteUnits)}`);
 | 
			
		||||
      this.warnedHeapCritical = false;
 | 
			
		||||
      this.maxHeapSize = 0;
 | 
			
		||||
      this.lastHeapLogTime = now;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
((): Server => new Server())();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								backend/src/utils/format.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								backend/src/utils/format.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
const byteUnits = ['B', 'kB', 'MB', 'GB', 'TB'];
 | 
			
		||||
 | 
			
		||||
export function getBytesUnit(bytes: number): string {
 | 
			
		||||
  if (isNaN(bytes) || !isFinite(bytes)) {
 | 
			
		||||
    return 'B';
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  let unitIndex = 0;
 | 
			
		||||
  while (unitIndex < byteUnits.length && bytes > 1024) {
 | 
			
		||||
    unitIndex++;
 | 
			
		||||
    bytes /= 1024;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return byteUnits[unitIndex];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function formatBytes(bytes: number, toUnit: string, skipUnit = false): string {
 | 
			
		||||
  if (isNaN(bytes) || !isFinite(bytes)) {
 | 
			
		||||
    return `${bytes}`;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  let unitIndex = 0;
 | 
			
		||||
  while (unitIndex < byteUnits.length && (toUnit && byteUnits[unitIndex] !== toUnit || (!toUnit && bytes > 1024))) {
 | 
			
		||||
    unitIndex++;
 | 
			
		||||
    bytes /= 1024;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return `${bytes.toFixed(2)}${skipUnit ? '' : ' ' + byteUnits[unitIndex]}`;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user