From 3113e5d278b5edff6a56c11e786de31472603a66 Mon Sep 17 00:00:00 2001 From: Oda <102867384+CryptoOda@users.noreply.github.com> Date: Mon, 21 Apr 2025 04:21:40 +0700 Subject: [PATCH] Aspire (#17) * add aspire * add healthchecks --- .../Managing.Api.Workers.csproj | 4 + src/Managing.Api.Workers/Program.cs | 42 ++++++- .../appsettings.Khalid.json | 24 ---- .../appsettings.Lowpro.json | 39 ------ .../appsettings.Production.json | 31 +++++ src/Managing.Api.Workers/appsettings.json | 3 + src/Managing.Api/Managing.Api.csproj | 4 + src/Managing.Api/Program.cs | 41 +++++++ src/Managing.Api/appsettings.Khalid.json | 34 ------ src/Managing.Api/appsettings.Production.json | 31 +++++ src/Managing.Api/appsettings.json | 2 +- .../Managing.Aspire.AppHost.csproj | 21 ++++ src/Managing.Aspire.AppHost/Program.cs | 13 ++ .../appsettings.Development.json | 8 ++ .../appsettings.Oda.json | 26 ++++ .../appsettings.ProdLocal.json | 19 +++ src/Managing.Aspire.AppHost/appsettings.json | 9 ++ .../Extensions.cs | 114 ++++++++++++++++++ .../Managing.Aspire.ServiceDefaults.csproj | 23 ++++ src/Managing.Bootstrap/WorkersBootstrap.cs | 5 +- src/Managing.Web3Proxy/src/routes/home.ts | 4 + src/Managing.sln | 20 +++ src/dotnet9-sdk-installer.pkg | 1 + src/run-aspire.sh | 9 ++ 24 files changed, 427 insertions(+), 100 deletions(-) delete mode 100644 src/Managing.Api.Workers/appsettings.Khalid.json delete mode 100644 src/Managing.Api.Workers/appsettings.Lowpro.json create mode 100644 src/Managing.Api.Workers/appsettings.Production.json delete mode 100644 src/Managing.Api/appsettings.Khalid.json create mode 100644 src/Managing.Api/appsettings.Production.json create mode 100644 src/Managing.Aspire.AppHost/Managing.Aspire.AppHost.csproj create mode 100644 src/Managing.Aspire.AppHost/Program.cs create mode 100644 src/Managing.Aspire.AppHost/appsettings.Development.json create mode 100644 src/Managing.Aspire.AppHost/appsettings.Oda.json create mode 100644 src/Managing.Aspire.AppHost/appsettings.ProdLocal.json create mode 100644 src/Managing.Aspire.AppHost/appsettings.json create mode 100644 src/Managing.Aspire.ServiceDefaults/Extensions.cs create mode 100644 src/Managing.Aspire.ServiceDefaults/Managing.Aspire.ServiceDefaults.csproj create mode 100644 src/dotnet9-sdk-installer.pkg create mode 100755 src/run-aspire.sh diff --git a/src/Managing.Api.Workers/Managing.Api.Workers.csproj b/src/Managing.Api.Workers/Managing.Api.Workers.csproj index 55d4c7a..5037374 100644 --- a/src/Managing.Api.Workers/Managing.Api.Workers.csproj +++ b/src/Managing.Api.Workers/Managing.Api.Workers.csproj @@ -11,6 +11,9 @@ + + + @@ -29,6 +32,7 @@ + diff --git a/src/Managing.Api.Workers/Program.cs b/src/Managing.Api.Workers/Program.cs index cc91910..8aa3278 100644 --- a/src/Managing.Api.Workers/Program.cs +++ b/src/Managing.Api.Workers/Program.cs @@ -8,18 +8,43 @@ using Managing.Core.Middleawares; using Managing.Infrastructure.Databases.InfluxDb.Models; using Managing.Infrastructure.Databases.MongoDb.Configurations; using Managing.Infrastructure.Evm.Models.Privy; +using Microsoft.Extensions.ServiceDiscovery; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; using NSwag; using NSwag.Generation.Processors.Security; using Serilog; using Serilog.Events; using Serilog.Sinks.Elasticsearch; +using HealthChecks.UI.Client; using OpenApiSecurityRequirement = Microsoft.OpenApi.Models.OpenApiSecurityRequirement; using OpenApiSecurityScheme = NSwag.OpenApiSecurityScheme; // Builder var builder = WebApplication.CreateBuilder(args); -// builder.WebHost.UseUrls("http://localhost:5001"); + +// 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"]; + + // Add service discovery for Aspire + builder.Services.AddServiceDiscovery(); + + // 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); builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json"); @@ -152,6 +177,21 @@ app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapHub("/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 + }); + + endpoints.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + } }); app.Run(); \ No newline at end of file diff --git a/src/Managing.Api.Workers/appsettings.Khalid.json b/src/Managing.Api.Workers/appsettings.Khalid.json deleted file mode 100644 index d9754cb..0000000 --- a/src/Managing.Api.Workers/appsettings.Khalid.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "ManagingDatabase": { - "ConnectionString": "mongodb://localhost:27017", - "DatabaseName": "ManagingDb", - }, - "InfluxDb": { - "Url": "http://localhost:8086/", - "Organization": "", - "Token": "" - }, - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Information", - "System": "Warning" - } - } - }, - "ElasticConfiguration": { - "Uri": "http://localhost:9200" - }, - "AllowedHosts": "*" -} \ No newline at end of file diff --git a/src/Managing.Api.Workers/appsettings.Lowpro.json b/src/Managing.Api.Workers/appsettings.Lowpro.json deleted file mode 100644 index 72246f9..0000000 --- a/src/Managing.Api.Workers/appsettings.Lowpro.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "ManagingDatabase": { - "ConnectionString": "mongodb://managingdb:27017", - "DatabaseName": "ManagingDb" - }, - "InfluxDb": { - "Url": "http://influxdb:8086", - "Token": "OPjdwQBmKr0zQecJ10IDQ4bt32oOJzmFp687QWWzbGeyH0R-gCA6HnXI_B0oQ_InPmSUXKFje8DSAUPbY0hn-w==", - "Organization": "managing-org" - }, - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Information", - "System": "Warning" - } - } - }, - "ElasticConfiguration": { - "Uri": "http://elasticsearch:9200" - }, - "Discord": { - "ApplicationId": "966075382002516031", - "PublicKey": "63028f6bb740cd5d26ae0340b582dee2075624011b28757436255fc002ca8a7c", - "TokenId": "OTY2MDc1MzgyMDAyNTE2MDMx.Yl8dzw.xpeIAaMwGrwTNY4r9JYv0ebzb-U", - - "SignalChannelId": 1134858150667898910, - "TradesChannelId": 1134858092530634864, - "TroublesChannelId": 1134858233031446671, - "CopyTradingChannelId": 1134857874896588881, - "RequestsChannelId": 1018589494968078356, - "LeaderboardChannelId": 1133169725237633095, - "NoobiesboardChannelId": 1133504653485690940, - "ButtonExpirationMinutes": 10 - - }, - "AllowedHosts": "*" -} diff --git a/src/Managing.Api.Workers/appsettings.Production.json b/src/Managing.Api.Workers/appsettings.Production.json new file mode 100644 index 0000000..31b8273 --- /dev/null +++ b/src/Managing.Api.Workers/appsettings.Production.json @@ -0,0 +1,31 @@ +{ + "ManagingDatabase": { + "ConnectionString": "mongodb://admin:r8oJiDIKbsEi@srv-captain--mongo-db:27017/?authMechanism=SCRAM-SHA-256", + "DatabaseName": "ManagingDb" + }, + "InfluxDb": { + "Url": "http://srv-captain--influx-db:8086/", + "Organization": "managing-org", + "Token": "eOuXcXhH7CS13Iw4CTiDDpRjIjQtEVPOloD82pLPOejI4n0BsEj1YzUw0g3Cs1mdDG5m-RaxCavCMsVTtS5wIQ==" + }, + "Privy": { + "AppId": "cm6f47n1l003jx7mjwaembhup", + "AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Information", + "System": "Warning" + } + } + }, + "Web3Proxy": { + "BaseUrl": "http://srv-captain--web3-proxy:4111" + }, + "ElasticConfiguration": { + "Uri": "http://elasticsearch:9200" + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/src/Managing.Api.Workers/appsettings.json b/src/Managing.Api.Workers/appsettings.json index f101036..779fe22 100644 --- a/src/Managing.Api.Workers/appsettings.json +++ b/src/Managing.Api.Workers/appsettings.json @@ -20,6 +20,9 @@ "ElasticConfiguration": { "Uri": "http://elasticsearch:9200" }, + "Web3Proxy": { + "BaseUrl": "http://localhost:4111" + }, "Discord": { "BotActivity": "with jobs", "HandleUserAction": true, diff --git a/src/Managing.Api/Managing.Api.csproj b/src/Managing.Api/Managing.Api.csproj index 950da1c..182137d 100644 --- a/src/Managing.Api/Managing.Api.csproj +++ b/src/Managing.Api/Managing.Api.csproj @@ -11,6 +11,9 @@ + + + @@ -30,6 +33,7 @@ + diff --git a/src/Managing.Api/Program.cs b/src/Managing.Api/Program.cs index fbcc1e4..84d4c8a 100644 --- a/src/Managing.Api/Program.cs +++ b/src/Managing.Api/Program.cs @@ -18,11 +18,37 @@ using NSwag.Generation.Processors.Security; using Serilog; using Serilog.Events; using Serilog.Sinks.Elasticsearch; +using Microsoft.Extensions.ServiceDiscovery; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; +using HealthChecks.UI.Client; using OpenApiSecurityRequirement = Microsoft.OpenApi.Models.OpenApiSecurityRequirement; using OpenApiSecurityScheme = NSwag.OpenApiSecurityScheme; // Builder var builder = WebApplication.CreateBuilder(args); + +// Set up Aspire telemetry and health checks when enabled, in all environments +if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPIRE_ENABLED"))) +{ + // Add Service Defaults - using extension methods directly + builder.Services.AddServiceDiscovery(); + builder.Services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + 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 specific health checks for databases and other services + builder.Services.AddHealthChecks() + .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.Configuration.SetBasePath(AppContext.BaseDirectory); builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json") @@ -174,6 +200,21 @@ app.UseEndpoints(endpoints => endpoints.MapHub("/bothub"); endpoints.MapHub("/backtesthub"); endpoints.MapHub("/candlehub"); + + // 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 + }); + + endpoints.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + } }); app.Run(); \ No newline at end of file diff --git a/src/Managing.Api/appsettings.Khalid.json b/src/Managing.Api/appsettings.Khalid.json deleted file mode 100644 index 46bd192..0000000 --- a/src/Managing.Api/appsettings.Khalid.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "ManagingDatabase": { - "ConnectionString": "mongodb://localhost:27017", - "DatabaseName": "ManagingDb" - }, - "InfluxDb": { - "Url": "http://localhost:8086/", - "Organization": "", - "Token": "" - }, - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Information", - "System": "Warning" - } - } - }, - "ElasticConfiguration": { - "Uri": "http://elasticsearch:9200" - }, - "Discord": { - "ApplicationId": "", - "PublicKey": "", - "SignalChannelId": 1018897743118340180, - "TroublesChannelId": 1018897743118340180, - "TradesChannelId": 1020457417877753886, - "RequestChannelId": 1020463151034138694, - "RequestsChannelId": 1020463151034138694, - "ButtonExpirationMinutes": 2 - }, - "AllowedHosts": "*" -} \ No newline at end of file diff --git a/src/Managing.Api/appsettings.Production.json b/src/Managing.Api/appsettings.Production.json new file mode 100644 index 0000000..ab0e66a --- /dev/null +++ b/src/Managing.Api/appsettings.Production.json @@ -0,0 +1,31 @@ +{ + "ManagingDatabase": { + "ConnectionString": "mongodb://admin:r8oJiDIKbsEi@srv-captain--mongo-db:27017/?authMechanism=SCRAM-SHA-256", + "DatabaseName": "ManagingDb" + }, + "InfluxDb": { + "Url": "http://srv-captain--influx-db:8086/", + "Organization": "managing-org", + "Token": "eOuXcXhH7CS13Iw4CTiDDpRjIjQtEVPOloD82pLPOejI4n0BsEj1YzUw0g3Cs1mdDG5m-RaxCavCMsVTtS5wIQ==" + }, + "Privy": { + "AppId": "cm6f47n1l003jx7mjwaembhup", + "AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF" + }, + "Web3Proxy": { + "BaseUrl": "http://srv-captain--web3-proxy:4111" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Information", + "System": "Warning" + } + } + }, + "ElasticConfiguration": { + "Uri": "http://elasticsearch:9200" + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/src/Managing.Api/appsettings.json b/src/Managing.Api/appsettings.json index 42f15d9..afd77b0 100644 --- a/src/Managing.Api/appsettings.json +++ b/src/Managing.Api/appsettings.json @@ -22,7 +22,7 @@ "Token": "" }, "Web3Proxy": { - "BaseUrl": "http://localhost:3000" + "BaseUrl": "http://localhost:4111" }, "Serilog": { "MinimumLevel": { diff --git a/src/Managing.Aspire.AppHost/Managing.Aspire.AppHost.csproj b/src/Managing.Aspire.AppHost/Managing.Aspire.AppHost.csproj new file mode 100644 index 0000000..fb5c171 --- /dev/null +++ b/src/Managing.Aspire.AppHost/Managing.Aspire.AppHost.csproj @@ -0,0 +1,21 @@ + + + + Exe + net8.0 + enable + enable + true + 2d8fdbdd-b3e0-4716-8e00-56064804c76a + + + + + + + + + + + + diff --git a/src/Managing.Aspire.AppHost/Program.cs b/src/Managing.Aspire.AppHost/Program.cs new file mode 100644 index 0000000..0f8add3 --- /dev/null +++ b/src/Managing.Aspire.AppHost/Program.cs @@ -0,0 +1,13 @@ +var builder = DistributedApplication.CreateBuilder(args); + +// Add API projects +var managingApi = builder.AddProject("managing-api"); +var workersApi = builder.AddProject("worker-api"); + +// No need to add containers - your APIs will use their existing connection strings +// from their respective appsettings.json files + +// Connect services to resources +workersApi.WithReference(managingApi); + +builder.Build().Run(); \ No newline at end of file diff --git a/src/Managing.Aspire.AppHost/appsettings.Development.json b/src/Managing.Aspire.AppHost/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/src/Managing.Aspire.AppHost/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/Managing.Aspire.AppHost/appsettings.Oda.json b/src/Managing.Aspire.AppHost/appsettings.Oda.json new file mode 100644 index 0000000..2416fa0 --- /dev/null +++ b/src/Managing.Aspire.AppHost/appsettings.Oda.json @@ -0,0 +1,26 @@ +{ + "ManagingDatabase": { + "ConnectionString": "mongodb://localhost:27017", + "DatabaseName": "ManagingDb" + }, + "InfluxDb": { + "Url": "http://localhost:8086/", + "Organization": "managing-org", + "Token": "Fw2FPL2OwTzDHzSbR2Sd5xs0EKQYy00Q-hYKYAhr9cC1_q5YySONpxuf_Ck0PTjyUiF13xXmi__bu_pXH-H9zA==" + }, + "Privy": { + "AppId": "cm6f47n1l003jx7mjwaembhup", + "AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF" + }, + "Discord": { + "ApplicationId": "", + "PublicKey": "", + "TokenId": "", + "SignalChannelId": 966080506473099314, + "TradesChannelId": 998374177763491851, + "TroublesChannelId": 1015761955321040917, + "RequestsChannelId": 1018589494968078356, + "ButtonExpirationMinutes": 2 + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/src/Managing.Aspire.AppHost/appsettings.ProdLocal.json b/src/Managing.Aspire.AppHost/appsettings.ProdLocal.json new file mode 100644 index 0000000..546af77 --- /dev/null +++ b/src/Managing.Aspire.AppHost/appsettings.ProdLocal.json @@ -0,0 +1,19 @@ +{ + "ManagingDatabase": { + "ConnectionString": "mongodb://admin:r8oJiDIKbsEi@mongo-db.apps.managing.live:27017/?authMechanism=SCRAM-SHA-256", + "DatabaseName": "ManagingDb" + }, + "InfluxDb": { + "Url": "https://influx-db.apps.managing.live", + "Organization": "managing-org", + "Token": "eOuXcXhH7CS13Iw4CTiDDpRjIjQtEVPOloD82pLPOejI4n0BsEj1YzUw0g3Cs1mdDG5m-RaxCavCMsVTtS5wIQ==" + }, + "Privy": { + "AppId": "cm6f47n1l003jx7mjwaembhup", + "AppSecret": "63Chz2z5M8TgR5qc8dznSLRAGTHTyPU4cjdQobrBF1Cx5tszZpTuFgyrRd7hZ2k6HpwDz3GEwQZzsCqHb8Z311bF" + }, + "ElasticConfiguration": { + "Uri": "http://elasticsearch:9200" + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/src/Managing.Aspire.AppHost/appsettings.json b/src/Managing.Aspire.AppHost/appsettings.json new file mode 100644 index 0000000..31c092a --- /dev/null +++ b/src/Managing.Aspire.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/src/Managing.Aspire.ServiceDefaults/Extensions.cs b/src/Managing.Aspire.ServiceDefaults/Extensions.cs new file mode 100644 index 0000000..aab5715 --- /dev/null +++ b/src/Managing.Aspire.ServiceDefaults/Extensions.cs @@ -0,0 +1,114 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting; + +// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults +public static class Extensions +{ + public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + + return builder; + } + + public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder) + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddAspNetCoreInstrumentation() + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder) + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder) + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Health check endpoints are now available in all environments + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + + return app; + } +} diff --git a/src/Managing.Aspire.ServiceDefaults/Managing.Aspire.ServiceDefaults.csproj b/src/Managing.Aspire.ServiceDefaults/Managing.Aspire.ServiceDefaults.csproj new file mode 100644 index 0000000..5875533 --- /dev/null +++ b/src/Managing.Aspire.ServiceDefaults/Managing.Aspire.ServiceDefaults.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + + + + + diff --git a/src/Managing.Bootstrap/WorkersBootstrap.cs b/src/Managing.Bootstrap/WorkersBootstrap.cs index 4cda135..63c2b30 100644 --- a/src/Managing.Bootstrap/WorkersBootstrap.cs +++ b/src/Managing.Bootstrap/WorkersBootstrap.cs @@ -64,7 +64,6 @@ public static class WorkersBootstrap services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddTransient, OpenPositionCommandHandler>(); services.AddTransient, ClosePositionCommandHandler>(); @@ -119,6 +118,10 @@ public static class WorkersBootstrap services.AddSingleton(); services.AddSingleton(); + // Web3Proxy Configuration + services.Configure(configuration.GetSection("Web3Proxy")); + services.AddTransient(); + // Messengers services.AddSingleton(); services.AddSingleton(); diff --git a/src/Managing.Web3Proxy/src/routes/home.ts b/src/Managing.Web3Proxy/src/routes/home.ts index 50710ec..9e9f873 100644 --- a/src/Managing.Web3Proxy/src/routes/home.ts +++ b/src/Managing.Web3Proxy/src/routes/home.ts @@ -16,6 +16,10 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => { return { message: 'Welcome to the official Web3 Proxy API!' } } ) + // Add health check endpoint + fastify.get('/health', async function () { + return { status: 'ok' } + }) } export default plugin diff --git a/src/Managing.sln b/src/Managing.sln index 5c5441a..5272634 100644 --- a/src/Managing.sln +++ b/src/Managing.sln @@ -66,6 +66,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.ABI.GmxV2", "Managing.ABI.GmxV2\Managing.ABI.GmxV2.csproj", "{4521E1A9-AF81-4CA8-8B4D-30C261ECE977}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Aspire.AppHost", "Managing.Aspire.AppHost\Managing.Aspire.AppHost.csproj", "{2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Aspire.ServiceDefaults", "Managing.Aspire.ServiceDefaults\Managing.Aspire.ServiceDefaults.csproj", "{F58949B8-4173-4F9E-83FF-B88FA2C5C849}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -226,6 +230,22 @@ Global {4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|Any CPU.Build.0 = Release|Any CPU {4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|x64.ActiveCfg = Release|Any CPU {4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|x64.Build.0 = Release|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|x64.Build.0 = Debug|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|Any CPU.Build.0 = Release|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|x64.ActiveCfg = Release|Any CPU + {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|x64.Build.0 = Release|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|x64.ActiveCfg = Debug|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|x64.Build.0 = Debug|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|Any CPU.Build.0 = Release|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|x64.ActiveCfg = Release|Any CPU + {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/dotnet9-sdk-installer.pkg b/src/dotnet9-sdk-installer.pkg new file mode 100644 index 0000000..3594dcd --- /dev/null +++ b/src/dotnet9-sdk-installer.pkg @@ -0,0 +1 @@ +GatewayExceptionResponse \ No newline at end of file diff --git a/src/run-aspire.sh b/src/run-aspire.sh new file mode 100755 index 0000000..fcf5024 --- /dev/null +++ b/src/run-aspire.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Set environment variables +export ASPIRE_ENABLED=true +export ASPNETCORE_ENVIRONMENT=Oda + +echo "Starting Aspire dashboard using existing MongoDB and InfluxDB..." +echo "Environment: $ASPNETCORE_ENVIRONMENT" +echo "Health endpoints will be available at /health and /alive on both APIs" +echo "Dashboard will be available at http://localhost:15888"