建議大家使用VS2019開發時把自帶的反編譯功能打開:
進入正題,首先上一個本節最終能實作的健康檢測UI界面: 本節實作的健康檢測是通過引用以下系列nuget進行的實作:github上有該包的實作方式,使用過程中可以參考源碼來編寫相關參數,github位址:https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks
在此也列一下清單吧,總共實作了對以下功能點的健康檢測功能:
以上主要是些通用的檢測點,如api是否正常,資料庫、redis等存儲庫是否正常,rabbitmq是否正常等,除此之後我們還可以自己擴充,比如與我們系統業務相關的功能資料檢測等,簡單的實作估計也就幾行代碼,主要看需求。
如何實作web或api、資料庫、redis等的狀态檢測呢?下面開始各種配置。
- 首先還是引用nuget包,我是引用了以下一堆,用哪個還是看需求:
- 配置Startup.cs檔案:
1 public class Startup
2 {
3 public Startup(IConfiguration configuration)
4 {
5 Configuration = configuration;
6 }
7 public IConfiguration Configuration { get; }
8
9 public void ConfigureServices(IServiceCollection services)
10 {
11 services.AddCustomHealthCheck(this.Configuration);
12
13 services.AddHealthChecksUI(setupSettings =>
14 {
15 //檢測站點,可以添加多條,UI中會把站點内的檢測點分組顯示(也可通過配置檔案實作)
16 setupSettings.AddHealthCheckEndpoint(name: "localhost-5000", uri: "http://localhost:5000/health");
17 //當檢測出異常結果時發送消息給api
18 setupSettings.AddWebhookNotification("webhook1",
19 uri: "http://localhost:5008/WeatherForecast/message",
20 payload: "{ \"message\": \"Webhook report for [[LIVENESS]]: [[FAILURE]] - Description: [[DESCRIPTIONS]]\"}",
21 restorePayload: "{ \"message\": \"[[LIVENESS]] is back to life\"}");
22 setupSettings.SetMinimumSecondsBetweenFailureNotifications(60);
23 setupSettings.SetEvaluationTimeInSeconds(10);
24 }).AddSqlServerStorage(Configuration["HealthStorageConnectionString"]);//資料庫持久化
25 //.AddInMemoryStorage();//記憶體持久化
26 }
27
28 public void ConfigureContainer(ContainerBuilder builder)
29 {
30 //autofac
31 }
32
33 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
34 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
35 {
36 if (env.IsDevelopment())
37 {
38 app.UseDeveloperExceptionPage();
39 }
40
41 app.UseRouting();
42 app.UseEndpoints(endpoints =>
43 {
44 endpoints.MapHealthChecks("/health", new HealthCheckOptions()
45 {
46 Predicate = _ => true,
47 ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
48 });
49 endpoints.MapHealthChecksUI();
50 });
51 }
52 }
其中AddCustomHealthCheck的實作如下,實作的檢測執行個體:
1 public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
2 {
3 var hcBuilder = services.AddHealthChecks();
4
5 hcBuilder.AddCheck("Jobs.MicrosoftBackgroundService-apiself", () => HealthCheckResult.Healthy());
6 hcBuilder.AddSqlServer(
7 configuration["ConnectionString"],
8 name: "Jobs.MicrosoftBackgroundService-sqlserver-check",
9 tags: new string[] { "sqlserverdb" });
10 hcBuilder.AddRabbitMQ(
11 $"amqp://{configuration["EventBusConnection"]}",
12 name: "Jobs.MicrosoftBackgroundService-rabbitmqbus-check",
13 tags: new string[] { "rabbitmqbus" });
14 hcBuilder.AddRedis(
15 configuration["RedisConnectionString"],
16 name: "Jobs.MicrosoftBackgroundService-redis-check",
17 tags: new string[] { "redisdb" });
18 hcBuilder.AddUrlGroup(new Uri(configuration["testApiUrl"]), name: "testApiUrl-check", tags: new string[] { "testApiUrl" });
19
20 return services;
21 }
可以看到這裡實作了對sqlserver資料庫、rebbitmq、redis、webapi的健康檢測,參數中最重要的是名稱及配置如連接配接字元串的資訊,如redis的連接配接字元串格式如何寫,我們可以通過檢視源碼來了解,此處實作redis的健康檢測源碼如下:
1 using Microsoft.Extensions.Diagnostics.HealthChecks;
2 using StackExchange.Redis;
3 using System;
4 using System.Collections.Concurrent;
5 using System.Threading;
6 using System.Threading.Tasks;
7
8 namespace HealthChecks.Redis
9 {
10 public class RedisHealthCheck : IHealthCheck
11 {
12 private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> _connections = new ConcurrentDictionary<string, ConnectionMultiplexer>();
13
14 private readonly string _redisConnectionString;
15
16 public RedisHealthCheck(string redisConnectionString)
17 {
18 _redisConnectionString = (redisConnectionString ?? throw new ArgumentNullException("redisConnectionString"));
19 }
20
21 public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
22 {
23 _ = 1;
24 try
25 {
26 if (!_connections.TryGetValue(_redisConnectionString, out ConnectionMultiplexer value))
27 {
28 value = await ConnectionMultiplexer.ConnectAsync(_redisConnectionString);
29 if (!_connections.TryAdd(_redisConnectionString, value))
30 {
31 value.Dispose();
32 value = _connections[_redisConnectionString];
33 }
34 }
35
36 await value.GetDatabase().PingAsync();
37 return HealthCheckResult.Healthy();
38 }
39 catch (Exception exception)
40 {
41 return new HealthCheckResult(context.Registration.FailureStatus, null, exception);
42 }
43 }
44 }
45 }
實作就幾行的代碼,同時我們看到這裡是通過StackExchange.Redis實作的redis連接配接,我們傳遞的連接配接字元串就很明顯了,如下:
"RedisConnectionString": "192.168.217.128:6379,defaultDatabase=1,password=123!@#..."
其他的相關參數也可以通過檢視源碼的方式來進行操作。。。
----------------------------------------------------------------------------------------------------------------------------------
設定資料持久化,可以通過檢視源碼得知此處是使用的EFCore,支援以下種類的持久化:
services中添加配置(記得引用需要的持久化nuget包):
services.AddSqlServerStorage(Configuration["HealthStorageConnectionString"]);
程式啟動後會自動根據配置的資料庫連接配接資訊建立資料表,大概就是配置資訊、目前狀态資訊、曆史記錄資訊。
如果健康檢測異常需要發送消息至api,可以添加以下配置:
具體參數格式也可通過源碼檢視,此處是post方式資料傳輸,關鍵源碼如下:
1 foreach (var webHook in _settings.Webhooks)
2 {
3 bool shouldNotify = webHook.ShouldNotifyFunc?.Invoke(report) ?? true;
4
5 if (!shouldNotify)
6 {
7 _logger.LogInformation("Webhook notification will not be sent because of user configuration");
8 continue;
9 };
10
11 if (!isHealthy)
12 {
13 failure = webHook.CustomMessageFunc?.Invoke(report) ?? GetFailedMessageFromContent(report);
14 description = webHook.CustomDescriptionFunc?.Invoke(report) ?? GetFailedDescriptionsFromContent(report);
15 }
16
17 var payload = isHealthy ? webHook.RestoredPayload : webHook.Payload;
18 payload = payload.Replace(Keys.LIVENESS_BOOKMARK, name)
19 .Replace(Keys.FAILURE_BOOKMARK, failure)
20 .Replace(Keys.DESCRIPTIONS_BOOKMARK, description);
21
22
23 Uri.TryCreate(webHook.Uri, UriKind.Absolute, out var absoluteUri);
24
25 if (absoluteUri == null || !absoluteUri.IsValidHealthCheckEndpoint())
26 {
27 Uri.TryCreate(_serverAddressesService.AbsoluteUriFromRelative(webHook.Uri), UriKind.Absolute, out absoluteUri);
28 }
29
30 await SendRequest(absoluteUri, webHook.Name, payload);
31 }
可以看到此處的Webhooks可以配置多個
1 private async Task SendRequest(Uri uri, string name, string payloadContent)
2 {
3 try
4 {
5 var payload = new StringContent(payloadContent, Encoding.UTF8, Keys.DEFAULT_RESPONSE_CONTENT_TYPE);
6 var response = await _httpClient.PostAsync(uri, payload);
7 if (!response.IsSuccessStatusCode)
8 {
9 _logger.LogError("The webhook notification has not executed successfully for {name} webhook. The error code is {statuscode}.", name, response.StatusCode);
10 }
11
12 }
13 catch (Exception exception)
14 {
15 _logger.LogError($"The failure notification for {name} has not executed successfully.", exception);
16 }
17 }
我們可以通過api接收異常消息後添加日志或進行發送郵件等提醒資訊。
最後如果要配置UI界面,隻需在endpoint中添加配置:
1 app.UseEndpoints(endpoints =>
2 {
3 endpoints.MapHealthChecks("/health", new HealthCheckOptions()
4 {
5 Predicate = _ => true,
6 ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
7 });//要進行該站點檢測應添加此代碼
8 endpoints.MapHealthChecksUI();//添加UI界面支援
9 });
寫的比較散,希望對大家學習有一絲絲幫助~~
作者:屈魯奇
出處:https://www.cnblogs.com/quluqi
聯系:[email protected] QQ:496195435
本文版權歸作者和部落格園共有,歡迎轉載,但必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。如有問題或建議,請多多賜教,非常感謝。