Display healthcheck on prod
This commit is contained in:
@@ -26,23 +26,19 @@ 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
|
var mongoConnectionString = builder.Configuration.GetSection(Constants.Databases.MongoDb)["ConnectionString"];
|
||||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED")))
|
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"];
|
// Add service discovery for Aspire
|
||||||
var web3ProxyUrl = builder.Configuration.GetSection("Web3Proxy")["BaseUrl"];
|
builder.Services.AddServiceDiscovery();
|
||||||
|
|
||||||
// Add service discovery for Aspire
|
// Configure health checks
|
||||||
builder.Services.AddServiceDiscovery();
|
builder.Services.AddHealthChecks()
|
||||||
|
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"])
|
||||||
// Configure health checks
|
.AddMongoDb(mongoConnectionString, name: "mongodb", tags: ["database"])
|
||||||
builder.Services.AddHealthChecks()
|
.AddUrlGroup(new Uri($"{influxUrl}/health"), name: "influxdb", tags: ["database"])
|
||||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"])
|
.AddUrlGroup(new Uri($"{web3ProxyUrl}/health"), name: "web3proxy", tags: ["api"]);
|
||||||
.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.WebHost.UseUrls("http://localhost:5001");
|
||||||
builder.Configuration.SetBasePath(AppContext.BaseDirectory);
|
builder.Configuration.SetBasePath(AppContext.BaseDirectory);
|
||||||
@@ -177,21 +173,17 @@ 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
|
endpoints.MapHealthChecks("/health", new HealthCheckOptions
|
||||||
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED")))
|
|
||||||
{
|
{
|
||||||
endpoints.MapHealthChecks("/health", new HealthCheckOptions
|
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||||
{
|
});
|
||||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
|
||||||
});
|
endpoints.MapHealthChecks("/alive", new HealthCheckOptions
|
||||||
|
{
|
||||||
endpoints.MapHealthChecks("/alive", new HealthCheckOptions
|
Predicate = r => r.Tags.Contains("live"),
|
||||||
{
|
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||||
Predicate = r => r.Tags.Contains("live"),
|
});
|
||||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.Run();
|
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 { 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 = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user