Fixing metrics (#2395)

* Fixing metrics

* run prettier
This commit is contained in:
sunghyunkang1111
2026-03-02 11:32:51 -06:00
committed by GitHub
parent dbe26654f1
commit 9496cf83ee
2 changed files with 30 additions and 8 deletions
+18
View File
@@ -105,6 +105,23 @@ class ScenarioMonitor {
}); });
ctx.timeoutId = window.setTimeout(() => { ctx.timeoutId = window.setTimeout(() => {
const missingPhases = ctx.config.requiredPhases.filter((p) => !ctx.completed.has(p));
this.devLog(
`timeout: ${scenario} | missing=[${missingPhases.join(", ")}] | completed=[${Array.from(ctx.completed).join(
", ",
)}] | documentHidden=${document.hidden} | hasExpectedFailure=${ctx.hasExpectedFailure}`,
);
traceMark(Action.MetricsScenario, {
event: "scenario_timeout",
scenario,
missingPhases: missingPhases.join(","),
completedPhases: Array.from(ctx.completed).join(","),
documentHidden: document.hidden,
hasExpectedFailure: ctx.hasExpectedFailure,
});
// If an expected failure occurred (auth, firewall, etc.), emit healthy instead of unhealthy // If an expected failure occurred (auth, firewall, etc.), emit healthy instead of unhealthy
const healthy = ctx.hasExpectedFailure; const healthy = ctx.hasExpectedFailure;
this.emit(ctx, healthy, true); this.emit(ctx, healthy, true);
@@ -288,6 +305,7 @@ class ScenarioMonitor {
scenario: ctx.scenario, scenario: ctx.scenario,
healthy, healthy,
timedOut, timedOut,
documentHidden: document.hidden,
platform, platform,
api, api,
durationMs: finalSnapshot.durationMs, durationMs: finalSnapshot.durationMs,
+12 -8
View File
@@ -1,24 +1,26 @@
import React from "react"; import React from "react";
import MetricScenario from "./MetricEvents"; import MetricScenario from "./MetricEvents";
import { useMetricScenario } from "./MetricScenarioProvider"; import { scenarioMonitor } from "./ScenarioMonitor";
import { ApplicationMetricPhase, CommonMetricPhase } from "./ScenarioConfig"; import { ApplicationMetricPhase, CommonMetricPhase } from "./ScenarioConfig";
/** /**
* Hook to automatically complete the Interactive phase when the component becomes interactive. * Hook to automatically complete the Interactive phase when the component becomes interactive.
* Uses requestAnimationFrame to complete after the browser has painted. * Uses requestAnimationFrame to complete after the browser has painted.
*
* Calls scenarioMonitor directly (not via React context) so that the effect dependencies
* are only [scenario, enabled] — both stable primitives. This prevents re-renders from
* cancelling the pending rAF due to an unstable context function reference.
*/ */
export function useInteractive(scenario: MetricScenario, enabled = true) { export function useInteractive(scenario: MetricScenario, enabled = true) {
const { completePhase } = useMetricScenario();
React.useEffect(() => { React.useEffect(() => {
if (!enabled) { if (!enabled) {
return undefined; return undefined;
} }
const id = requestAnimationFrame(() => { const id = requestAnimationFrame(() => {
completePhase(scenario, CommonMetricPhase.Interactive); scenarioMonitor.completePhase(scenario, CommonMetricPhase.Interactive);
}); });
return () => cancelAnimationFrame(id); return () => cancelAnimationFrame(id);
}, [scenario, completePhase, enabled]); }, [scenario, enabled]);
} }
/** /**
@@ -26,18 +28,20 @@ export function useInteractive(scenario: MetricScenario, enabled = true) {
* Tracks tree rendering and completes Interactive phase. * Tracks tree rendering and completes Interactive phase.
* Only completes DatabaseTreeRendered if the database fetch was successful. * Only completes DatabaseTreeRendered if the database fetch was successful.
* Note: Scenario must be started before databases are fetched (in refreshExplorer). * Note: Scenario must be started before databases are fetched (in refreshExplorer).
*
* Calls scenarioMonitor directly (not via React context) for the same stability reason
* as useInteractive — avoids effect re-runs from unstable context function references.
*/ */
export function useDatabaseLoadScenario(databaseTreeNodes: unknown[], fetchSucceeded: boolean) { export function useDatabaseLoadScenario(databaseTreeNodes: unknown[], fetchSucceeded: boolean) {
const { completePhase } = useMetricScenario();
const hasCompletedTreeRenderRef = React.useRef(false); const hasCompletedTreeRenderRef = React.useRef(false);
// Track DatabaseTreeRendered phase (only if fetch succeeded) // Track DatabaseTreeRendered phase (only if fetch succeeded)
React.useEffect(() => { React.useEffect(() => {
if (!hasCompletedTreeRenderRef.current && fetchSucceeded) { if (!hasCompletedTreeRenderRef.current && fetchSucceeded) {
hasCompletedTreeRenderRef.current = true; hasCompletedTreeRenderRef.current = true;
completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered); scenarioMonitor.completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered);
} }
}, [databaseTreeNodes, fetchSucceeded, completePhase]); }, [databaseTreeNodes, fetchSucceeded]);
// Track Interactive phase // Track Interactive phase
useInteractive(MetricScenario.DatabaseLoad); useInteractive(MetricScenario.DatabaseLoad);