All files / memory-monitor/src/hooks useAutoGC.ts

45.83% Statements 11/24
22.22% Branches 4/18
75% Functions 3/4
45.83% Lines 11/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129                                                                                                                      64x   64x 64x     64x 27x         64x       64x   51x 51x                                                           64x                           64x            
import { useEffect, useRef, useCallback } from "react";
import { AUTO_GC_COOLDOWN_MS } from "../constants";
import type { AutoGCEventData } from "../types";
 
/**
 * Options for useAutoGC hook
 */
export interface UseAutoGCOptions {
  /** Whether auto-GC is enabled */
  enabled: boolean;
  /** Usage threshold to trigger GC (0-100) */
  threshold: number | null;
  /** Current usage percentage */
  usagePercentage: number | null;
  /** Function to request GC */
  requestGC: () => void;
  /** Callback when auto-GC is triggered */
  onAutoGC?: (data: AutoGCEventData) => void;
  /** Cooldown period in milliseconds */
  cooldownMs?: number;
}
 
/**
 * Return type for useAutoGC hook
 */
export interface UseAutoGCReturn {
  /** Timestamp of last GC trigger */
  lastTriggered: number | null;
  /** Whether GC is currently on cooldown */
  isOnCooldown: boolean;
  /** Manually trigger GC (bypasses cooldown) */
  forceGC: () => void;
}
 
/**
 * Hook to automatically trigger garbage collection when memory threshold is exceeded
 *
 * @param options - Configuration options
 * @returns GC state and control functions
 *
 * @example
 * ```tsx
 * const { lastTriggered, isOnCooldown } = useAutoGC({
 *   enabled: true,
 *   threshold: 85,
 *   usagePercentage: currentUsage,
 *   requestGC: () => monitor.requestGC(),
 *   onAutoGC: (data) => console.log('Auto-GC triggered', data),
 * });
 * ```
 */
export function useAutoGC(options: UseAutoGCOptions): UseAutoGCReturn {
  const {
    enabled,
    threshold,
    usagePercentage,
    requestGC,
    onAutoGC,
    cooldownMs = AUTO_GC_COOLDOWN_MS,
  } = options;
 
  const lastTriggeredRef = useRef<number | null>(null);
  const onAutoGCRef = useRef(onAutoGC);
 
  // Update callback ref
  useEffect(() => {
    onAutoGCRef.current = onAutoGC;
  }, [onAutoGC]);
 
  // Check if on cooldown
  const isOnCooldown =
    lastTriggeredRef.current !== null &&
    Date.now() - lastTriggeredRef.current < cooldownMs;
 
  // Auto-GC effect
  useEffect(() => {
    // Skip if disabled or no threshold set
    Eif (!enabled || threshold === null || usagePercentage === null) {
      return;
    }
 
    // Skip if usage is below threshold
    if (usagePercentage < threshold) {
      return;
    }
 
    // Skip if on cooldown
    const now = Date.now();
    if (
      lastTriggeredRef.current !== null &&
      now - lastTriggeredRef.current < cooldownMs
    ) {
      return;
    }
 
    // Trigger GC
    lastTriggeredRef.current = now;
    requestGC();
 
    // Call callback
    onAutoGCRef.current?.({
      threshold,
      usage: usagePercentage,
      timestamp: now,
    });
  }, [enabled, threshold, usagePercentage, requestGC, cooldownMs]);
 
  // Force GC function (bypasses cooldown)
  const forceGC = useCallback(() => {
    const now = Date.now();
    lastTriggeredRef.current = now;
    requestGC();
 
    if (threshold !== null && usagePercentage !== null) {
      onAutoGCRef.current?.({
        threshold,
        usage: usagePercentage,
        timestamp: now,
      });
    }
  }, [requestGC, threshold, usagePercentage]);
 
  return {
    lastTriggered: lastTriggeredRef.current,
    isOnCooldown,
    forceGC,
  };
}