From 8fbbaad670e3626d5b3ed224c46db5a215d3de02 Mon Sep 17 00:00:00 2001 From: shinchan-zhai Date: Mon, 23 Mar 2026 12:58:38 +0800 Subject: [PATCH] fix: graceful HTTP shutdown, add ErrorBoundary, fix chart responsive height - main.go: call server.Shutdown() on SIGTERM/SIGINT to drain in-flight requests - Add React ErrorBoundary component (catches render crashes, shows retry UI) - Wrap main content area and settings page with ErrorBoundary - Fix ChartTabs.tsx: replace runtime window.innerWidth check with Tailwind responsive class (h-[500px] md:h-[600px]) - Restarted backend with latest build (health endpoint now returns proper timestamp) --- main.go | 6 ++ web/src/App.tsx | 7 ++- web/src/components/charts/ChartTabs.tsx | 3 +- web/src/components/common/ErrorBoundary.tsx | 61 +++++++++++++++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 web/src/components/common/ErrorBoundary.tsx diff --git a/main.go b/main.go index 03297c98..eddb7419 100644 --- a/main.go +++ b/main.go @@ -181,6 +181,12 @@ func main() { <-quit logger.Info("📴 Shutdown signal received, closing system...") + // Gracefully shutdown HTTP server (drain in-flight requests) + if err := server.Shutdown(); err != nil { + logger.Warnf("⚠️ HTTP server shutdown error: %v", err) + } + logger.Info("✅ HTTP server stopped") + // Stop all traders traderManager.StopAll() logger.Info("✅ System shut down safely") diff --git a/web/src/App.tsx b/web/src/App.tsx index 211be224..e5237b51 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -18,6 +18,7 @@ import { StrategyMarketPage } from './pages/StrategyMarketPage' import { DataPage } from './pages/DataPage' import { LoginRequiredOverlay } from './components/auth/LoginRequiredOverlay' import HeaderBar from './components/common/HeaderBar' +import { ErrorBoundary } from './components/common/ErrorBoundary' import { LanguageProvider, useLanguage } from './contexts/LanguageContext' import { AuthProvider, useAuth } from './contexts/AuthContext' import { ConfirmDialogProvider } from './components/common/ConfirmDialog' @@ -396,7 +397,9 @@ function App() { onLoginRequired={handleLoginRequired} onPageChange={navigateToPage} /> - + + + ) } @@ -474,6 +477,7 @@ function App() { {/* Main Content with Page Transitions */}
+ +
{/* Footer */} diff --git a/web/src/components/charts/ChartTabs.tsx b/web/src/components/charts/ChartTabs.tsx index 8c9fde0e..4e237c0e 100644 --- a/web/src/components/charts/ChartTabs.tsx +++ b/web/src/components/charts/ChartTabs.tsx @@ -144,8 +144,7 @@ export function ChartTabs({ traderId, selectedSymbol, updateKey, exchangeId }: C return ( -
+
{/* Premium Professional Toolbar Mobile: Single row, horizontal scroll with gradient mask diff --git a/web/src/components/common/ErrorBoundary.tsx b/web/src/components/common/ErrorBoundary.tsx new file mode 100644 index 00000000..22540684 --- /dev/null +++ b/web/src/components/common/ErrorBoundary.tsx @@ -0,0 +1,61 @@ +import { Component, type ReactNode } from 'react' +import { AlertTriangle, RefreshCw } from 'lucide-react' + +interface Props { + children: ReactNode + fallback?: ReactNode +} + +interface State { + hasError: boolean + error: Error | null +} + +export class ErrorBoundary extends Component { + constructor(props: Props) { + super(props) + this.state = { hasError: false, error: null } + } + + static getDerivedStateFromError(error: Error): State { + return { hasError: true, error } + } + + componentDidCatch(error: Error, info: React.ErrorInfo) { + console.error('[ErrorBoundary] Uncaught error:', error, info.componentStack) + } + + handleReset = () => { + this.setState({ hasError: false, error: null }) + } + + render() { + if (this.state.hasError) { + if (this.props.fallback) return this.props.fallback + + return ( +
+ +

Something went wrong

+

+ An unexpected error occurred. You can try refreshing this section. +

+ {this.state.error && ( +

+ {this.state.error.message} +

+ )} + +
+ ) + } + + return this.props.children + } +}