Display healthcheck on prod
This commit is contained in:
@@ -26,23 +26,19 @@ using OpenApiSecurityScheme = NSwag.OpenApiSecurityScheme;
|
||||
// Builder
|
||||
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 influxUrl = builder.Configuration.GetSection(Constants.Databases.InfluxDb)["Url"];
|
||||
var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"];
|
||||
var mongoConnectionString = builder.Configuration.GetSection(Constants.Databases.MongoDb)["ConnectionString"];
|
||||
var influxUrl = builder.Configuration.GetSection(Constants.Databases.InfluxDb)["Url"];
|
||||
var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"];
|
||||
|
||||
// Add service discovery for Aspire
|
||||
builder.Services.AddServiceDiscovery();
|
||||
// Add service discovery for Aspire
|
||||
builder.Services.AddServiceDiscovery();
|
||||
|
||||
// Configure health checks
|
||||
builder.Services.AddHealthChecks()
|
||||
// Configure health checks
|
||||
builder.Services.AddHealthChecks()
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"])
|
||||
.AddMongoDb(mongoConnectionString, name: "mongodb", tags: ["database"])
|
||||
.AddUrlGroup(new Uri($"{influxUrl}/health"), name: "influxdb", tags: ["database"])
|
||||
.AddUrlGroup(new Uri($"{web3ProxyUrl}/health"), name: "web3proxy", tags: ["api"]);
|
||||
}
|
||||
|
||||
builder.WebHost.UseUrls("http://localhost:5001");
|
||||
builder.Configuration.SetBasePath(AppContext.BaseDirectory);
|
||||
@@ -178,9 +174,6 @@ app.UseEndpoints(endpoints =>
|
||||
endpoints.MapControllers();
|
||||
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
|
||||
{
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
@@ -191,7 +184,6 @@ app.UseEndpoints(endpoints =>
|
||||
Predicate = r => r.Tags.Contains("live"),
|
||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.Run();
|
||||
@@ -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
|
||||
@@ -3,6 +3,7 @@ import { useState } from 'react'
|
||||
import { Tabs } from '../../components/mollecules'
|
||||
|
||||
import AccountSettings from './account/accountSettings'
|
||||
import HealthChecks from './healthchecks/healthChecks'
|
||||
import MoneyManagementSettings from './moneymanagement/moneyManagement'
|
||||
import Theme from './theme'
|
||||
import DefaultConfig from './defaultConfig/defaultConfig'
|
||||
@@ -35,6 +36,11 @@ const tabs: TabsType = [
|
||||
index: 4,
|
||||
label: 'Quick Start Config',
|
||||
},
|
||||
{
|
||||
Component: HealthChecks,
|
||||
index: 5,
|
||||
label: 'Health Checks',
|
||||
},
|
||||
]
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
|
||||
Reference in New Issue
Block a user