Display healthcheck on prod

This commit is contained in:
2025-04-21 18:54:28 +07:00
parent c571130bb0
commit df5f7185c8
3 changed files with 191 additions and 31 deletions

View File

@@ -26,9 +26,6 @@ using OpenApiSecurityScheme = NSwag.OpenApiSecurityScheme;
// Builder // Builder
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add health checks when Aspire is enabled, in all environments
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED")))
{
var mongoConnectionString = builder.Configuration.GetSection(Constants.Databases.MongoDb)["ConnectionString"]; var mongoConnectionString = builder.Configuration.GetSection(Constants.Databases.MongoDb)["ConnectionString"];
var influxUrl = builder.Configuration.GetSection(Constants.Databases.InfluxDb)["Url"]; var influxUrl = builder.Configuration.GetSection(Constants.Databases.InfluxDb)["Url"];
var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"]; var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"];
@@ -42,7 +39,6 @@ if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED")))
.AddMongoDb(mongoConnectionString, name: "mongodb", tags: ["database"]) .AddMongoDb(mongoConnectionString, name: "mongodb", tags: ["database"])
.AddUrlGroup(new Uri($"{influxUrl}/health"), name: "influxdb", tags: ["database"]) .AddUrlGroup(new Uri($"{influxUrl}/health"), name: "influxdb", tags: ["database"])
.AddUrlGroup(new Uri($"{web3ProxyUrl}/health"), name: "web3proxy", tags: ["api"]); .AddUrlGroup(new Uri($"{web3ProxyUrl}/health"), name: "web3proxy", tags: ["api"]);
}
builder.WebHost.UseUrls("http://localhost:5001"); builder.WebHost.UseUrls("http://localhost:5001");
builder.Configuration.SetBasePath(AppContext.BaseDirectory); builder.Configuration.SetBasePath(AppContext.BaseDirectory);
@@ -178,9 +174,6 @@ app.UseEndpoints(endpoints =>
endpoints.MapControllers(); endpoints.MapControllers();
endpoints.MapHub<PositionHub>("/positionhub"); endpoints.MapHub<PositionHub>("/positionhub");
// Always add health check endpoints when Aspire is enabled, regardless of environment
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED")))
{
endpoints.MapHealthChecks("/health", new HealthCheckOptions endpoints.MapHealthChecks("/health", new HealthCheckOptions
{ {
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
@@ -191,7 +184,6 @@ app.UseEndpoints(endpoints =>
Predicate = r => r.Tags.Contains("live"), Predicate = r => r.Tags.Contains("live"),
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
}); });
}
}); });
app.Run(); app.Run();

View File

@@ -0,0 +1,162 @@
import React, { useEffect, useState } from 'react'
import useApiUrlStore from '../../../app/store/apiStore'
import { Table } from '../../../components/mollecules'
// Define health check response interface based on the provided example
interface HealthCheckEntry {
data: Record<string, any>
duration: string
status: string
tags: string[]
}
interface HealthCheckResponse {
status: string
totalDuration: string
entries: Record<string, HealthCheckEntry>
}
const HealthChecks: React.FC = () => {
const { apiUrl, workerUrl } = useApiUrlStore()
const [apiHealth, setApiHealth] = useState<HealthCheckResponse | null>(null)
const [workerHealth, setWorkerHealth] = useState<HealthCheckResponse | null>(null)
const [web3ProxyHealth, setWeb3ProxyHealth] = useState<HealthCheckResponse | null>(null)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
const fetchHealthChecks = async () => {
setIsLoading(true)
try {
// Fetch API health check
const apiResponse = await fetch(`${apiUrl}/health`)
if (apiResponse.ok) {
const data = await apiResponse.json()
setApiHealth(data)
}
// Fetch Worker health check
const workerResponse = await fetch(`${workerUrl}/health`)
if (workerResponse.ok) {
const data = await workerResponse.json()
setWorkerHealth(data)
}
// Fetch Web3Proxy health check - assuming it's accessible via the API
// This might need adjustment based on your actual deployment
const web3Response = await fetch(`${apiUrl.replace(':5000', ':5002')}/health`)
if (web3Response.ok) {
const data = await web3Response.json()
setWeb3ProxyHealth(data)
}
} catch (error) {
console.error('Error fetching health checks:', error)
} finally {
setIsLoading(false)
}
}
fetchHealthChecks()
}, [apiUrl, workerUrl])
// Helper function to prepare table data from health response
const prepareHealthData = (
service: string,
health: HealthCheckResponse | null
) => {
if (!health) {
return [
{
service,
component: 'N/A',
status: 'Unreachable',
duration: 'N/A',
tags: 'N/A',
},
]
}
// Convert entries to rows for the table
return Object.entries(health.entries).map(([key, entry]) => ({
service,
component: key,
status: entry.status,
duration: entry.duration,
tags: entry.tags.join(', '),
}))
}
// Combine all health check data for display
const healthData = [
...prepareHealthData('Managing API', apiHealth),
...prepareHealthData('Managing Worker', workerHealth),
...prepareHealthData('Web3 Proxy', web3ProxyHealth),
]
// Define columns for the table
const columns = React.useMemo(
() => [
{
Header: 'Service',
accessor: 'service',
disableSortBy: true,
disableFilters: true,
},
{
Header: 'Component',
accessor: 'component',
disableSortBy: true,
disableFilters: true,
},
{
Header: 'Status',
accessor: 'status',
Cell: ({ value }: { value: string }) => (
<span
className={`badge ${
value === 'Healthy'
? 'badge-success'
: value === 'Unreachable'
? 'badge-error'
: 'badge-warning'
}`}
>
{value}
</span>
),
disableSortBy: true,
disableFilters: true,
},
{
Header: 'Duration',
accessor: 'duration',
disableSortBy: true,
disableFilters: true,
},
{
Header: 'Tags',
accessor: 'tags',
disableSortBy: true,
disableFilters: true,
},
],
[]
)
return (
<div className="container mx-auto">
<h2 className="text-xl font-bold mb-4">System Health Status</h2>
{isLoading ? (
<progress className="progress progress-primary w-56"></progress>
) : (
<Table
columns={columns}
data={healthData}
showPagination={false}
/>
)}
</div>
)
}
export default HealthChecks

View File

@@ -3,6 +3,7 @@ import { useState } from 'react'
import { Tabs } from '../../components/mollecules' import { Tabs } from '../../components/mollecules'
import AccountSettings from './account/accountSettings' import AccountSettings from './account/accountSettings'
import HealthChecks from './healthchecks/healthChecks'
import MoneyManagementSettings from './moneymanagement/moneyManagement' import MoneyManagementSettings from './moneymanagement/moneyManagement'
import Theme from './theme' import Theme from './theme'
import DefaultConfig from './defaultConfig/defaultConfig' import DefaultConfig from './defaultConfig/defaultConfig'
@@ -35,6 +36,11 @@ const tabs: TabsType = [
index: 4, index: 4,
label: 'Quick Start Config', label: 'Quick Start Config',
}, },
{
Component: HealthChecks,
index: 5,
label: 'Health Checks',
},
] ]
const Settings: React.FC = () => { const Settings: React.FC = () => {