fix: reduce excessive POST /api/auto-mode/context-exists requests

Two changes:
1. Server: Skip morgan logging for context-exists endpoint (like health check)
2. UI: Use a stable fingerprint (feature IDs + statuses) instead of the
   unstable features array reference as the useEffect dependency. This
   prevents re-checking context for all features on every React Query
   refetch when the actual feature set hasn't changed.
This commit is contained in:
gsxdsm
2026-03-02 11:14:46 -08:00
parent 8218c48e67
commit 1c3d6434a8
2 changed files with 26 additions and 5 deletions

View File

@@ -261,7 +261,10 @@ morgan.token('status-colored', (_req, res) => {
app.use( app.use(
morgan(':method :url :status-colored', { morgan(':method :url :status-colored', {
// Skip when request logging is disabled or for health check endpoints // Skip when request logging is disabled or for health check endpoints
skip: (req) => !requestLoggingEnabled || req.url === '/api/health', skip: (req) =>
!requestLoggingEnabled ||
req.url === '/api/health' ||
req.url === '/api/auto-mode/context-exists',
}) })
); );
// CORS configuration // CORS configuration

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react'; import { useEffect, useMemo, useRef } from 'react';
import { getElectronAPI } from '@/lib/electron'; import { getElectronAPI } from '@/lib/electron';
import { createLogger } from '@automaker/utils/logger'; import { createLogger } from '@automaker/utils/logger';
import type { Feature } from '@/store/app-store'; import type { Feature } from '@/store/app-store';
@@ -68,10 +68,27 @@ export function useBoardEffects({
// Note: Running tasks sync is now handled by useAutoMode hook in BoardView // Note: Running tasks sync is now handled by useAutoMode hook in BoardView
// which correctly handles worktree/branch scoping. // which correctly handles worktree/branch scoping.
// Build a stable fingerprint of feature IDs + statuses so context checks
// only re-run when the set of features or their statuses actually change,
// not on every React Query refetch that produces a new array reference.
const featuresFingerprint = useMemo(() => {
return features
.map((f) => `${f.id}:${f.status}`)
.sort()
.join(',');
}, [features]);
// Keep a ref to the latest features array for use inside the effect
const featuresRef = useRef(features);
useEffect(() => {
featuresRef.current = features;
}, [features]);
// Check which features have context files // Check which features have context files
useEffect(() => { useEffect(() => {
const checkAllContexts = async () => { const checkAllContexts = async () => {
const featuresWithPotentialContext = features.filter( const currentFeatures = featuresRef.current;
const featuresWithPotentialContext = currentFeatures.filter(
(f) => (f) =>
f.status === 'backlog' || f.status === 'backlog' ||
f.status === 'merge_conflict' || f.status === 'merge_conflict' ||
@@ -99,10 +116,11 @@ export function useBoardEffects({
setFeaturesWithContext(newSet); setFeaturesWithContext(newSet);
}; };
if (features.length > 0 && !isLoading) { if (featuresFingerprint && !isLoading) {
checkAllContexts(); checkAllContexts();
} }
}, [features, isLoading, checkContextExists, setFeaturesWithContext]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [featuresFingerprint, isLoading, checkContextExists, setFeaturesWithContext]);
// Re-check context when a feature stops, completes, or errors // Re-check context when a feature stops, completes, or errors
// This ensures hasContext is updated even if the features array doesn't change // This ensures hasContext is updated even if the features array doesn't change