Skip to content

Commit 873f0aa

Browse files
committed
perf: make health check non-blocking for faster page load
Remove isCheckingHealth from the blocking condition so pages render immediately after auth. Health check now runs in background and shows a dismissable banner if API is unhealthy instead of full-page spinner.
1 parent 7e6ad8a commit 873f0aa

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

frontend/src/app/(home)/layout.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { DeleteOperationProvider } from '@/contexts/DeleteOperationContext';
1111
import { BillingProvider } from '@/contexts/BillingContext';
1212
import { useAccounts } from '@/hooks/use-accounts';
1313
import { Loader2 } from 'lucide-react';
14-
import { MaintenancePage } from '@/components/maintenance/maintenance-page';
1514
import { StatusOverlay } from '@/components/ui/status-overlay';
15+
import { ApiHealthBanner } from '@/components/ui/api-health-banner';
1616
import type { IMaintenanceNotice } from '@/lib/edge-flags';
1717
import { MaintenanceNotice } from './_components/maintenance-notice';
1818
import { MaintenanceBanner } from './_components/maintenance-banner';
@@ -37,6 +37,7 @@ export default function HomeLayout({
3737
const { user, isLoaded } = useUser();
3838
const [sidebarOpen, setSidebarOpen] = useState(false);
3939
const [isClient, setIsClient] = useState(false);
40+
const [showHealthBanner, setShowHealthBanner] = useState(true);
4041
const pathname = usePathname();
4142

4243
// TODO: Implement maintenance notice fetching from API or server component
@@ -97,27 +98,28 @@ export default function HomeLayout({
9798
);
9899
}
99100

100-
// Enhanced: Show loading state while checking auth or health
101-
if (!isClient || !isLoaded || isCheckingHealth) {
101+
// Health banner shown when API is unhealthy (non-blocking)
102+
const healthBanner = !isApiHealthy && !isCheckingHealth && showHealthBanner ? (
103+
<ApiHealthBanner onDismiss={() => setShowHealthBanner(false)} />
104+
) : null;
105+
106+
// Show loading state while checking auth (health check runs in background)
107+
if (!isClient || !isLoaded) {
102108
return (
103109
<div className="flex items-center justify-center min-h-screen">
104110
<Loader2 className="h-8 w-8 animate-spin text-primary" />
105111
</div>
106112
);
107113
}
108114

109-
// Enhanced: Show maintenance page if API is not healthy
110-
if (!isApiHealthy) {
111-
return <MaintenancePage />;
112-
}
113-
114115
// Enhanced: Graceful degradation - Don't render anything if not authenticated
115116
// Note: BillingProvider removed from unauthenticated branch - billing is only needed for authenticated users
116117
if (!user) {
117118
return (
118119
<div
119120
className={`w-full relative min-h-screen ${!isThreadPage ? 'gradient-home-bg' : 'bg-thread-panel'}`}
120121
>
122+
{healthBanner}
121123
{!isThreadPage && <Navbar sidebarOpen={false} />}
122124
<div className={isThreadPage ? "pt-0" : "pt-6"}>
123125
<Suspense fallback={<PageLoadingFallback />}>
@@ -142,6 +144,8 @@ export default function HomeLayout({
142144
<SidebarInset>
143145
{/* Enhanced: Maintenance banner */}
144146
{maintenanceBanner}
147+
{/* Health banner when API is unhealthy */}
148+
{healthBanner}
145149

146150
<div
147151
className={`w-full relative min-h-screen ${!isThreadPage ? 'gradient-home-bg' : 'bg-thread-panel'}`}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use client';
2+
3+
import { AlertTriangle, X, RefreshCw } from 'lucide-react';
4+
import { useApiHealth } from '@/hooks/react-query/usage/use-health';
5+
import { Button } from '@/components/ui/button';
6+
7+
interface ApiHealthBannerProps {
8+
onDismiss: () => void;
9+
}
10+
11+
export function ApiHealthBanner({ onDismiss }: ApiHealthBannerProps) {
12+
const { refetch, isLoading } = useApiHealth();
13+
14+
return (
15+
<div className="bg-yellow-500/10 border-b border-yellow-500/20 px-4 py-3">
16+
<div className="max-w-7xl mx-auto flex items-center justify-between gap-4">
17+
<div className="flex items-center gap-3">
18+
<AlertTriangle className="h-5 w-5 text-yellow-500 flex-shrink-0" />
19+
<p className="text-sm text-yellow-200">
20+
Some features may be unavailable. We&apos;re working on it.
21+
</p>
22+
</div>
23+
<div className="flex items-center gap-2">
24+
<Button
25+
variant="ghost"
26+
size="sm"
27+
onClick={() => refetch()}
28+
disabled={isLoading}
29+
className="text-yellow-200 hover:text-yellow-100"
30+
>
31+
<RefreshCw className={`h-4 w-4 mr-1 ${isLoading ? 'animate-spin' : ''}`} />
32+
Retry
33+
</Button>
34+
<Button
35+
variant="ghost"
36+
size="icon"
37+
onClick={onDismiss}
38+
className="text-yellow-200 hover:text-yellow-100"
39+
>
40+
<X className="h-4 w-4" />
41+
</Button>
42+
</div>
43+
</div>
44+
</div>
45+
);
46+
}

frontend/src/hooks/react-query/usage/use-health.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ export const useApiHealth = createQueryHook(
1111
staleTime: 5 * 60 * 1000, // 5 minutes - API health doesn't change frequently
1212
refetchInterval: false, // No wasteful background polling
1313
refetchOnWindowFocus: true, // Smart: check when user returns to tab
14-
retry: 3,
14+
retry: 1, // Reduced from 3 to 1 for faster failure (health check is non-blocking now)
1515
}
1616
);

0 commit comments

Comments
 (0)