Skip to content

Commit

Permalink
Consul deregistration using hosted service (#29)
Browse files Browse the repository at this point in the history
Consul deregistration using hosted service
  • Loading branch information
muphblu authored Sep 17, 2024
1 parent 62db7f5 commit 972a306
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 142 deletions.
30 changes: 12 additions & 18 deletions ATI.Services.Consul/ConsulDeregistrationExtension.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace ATI.Services.Consul
{
[PublicAPI]
public static class ConsulDeregistrationExtension
{
private const string DeregistrationAddress = "_internal/consul/deregister";
namespace ATI.Services.Consul;

public static IEndpointConventionBuilder MapConsulDeregistration(this IEndpointRouteBuilder builder,
string deregistrationAddress = null)
{
return builder.MapDelete(deregistrationAddress ?? DeregistrationAddress, DeregisterDelegate);
}
[PublicAPI]
public static class ConsulDeregistrationExtension
{
private const string DeregistrationAddress = "_internal/consul/deregister";

private static async Task DeregisterDelegate(HttpContext _)
{
await ConsulRegistrator.DeregisterInstanceAsync();
}
public static IEndpointConventionBuilder MapConsulDeregistration(this IEndpointRouteBuilder builder,
string deregistrationAddress = null)
{
var registrator = builder.ServiceProvider.GetService<ConsulRegistrator>();
return builder.MapDelete(deregistrationAddress ?? DeregistrationAddress, async _ => await registrator.DeregisterInstanceAsync());
}
}
16 changes: 8 additions & 8 deletions ATI.Services.Consul/ConsulExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;

namespace ATI.Services.Consul
namespace ATI.Services.Consul;

public static class ConsulExtensions
{
public static class ConsulExtensions
[PublicAPI]
public static void AddConsul(this IServiceCollection services)
{
[PublicAPI]
public static void AddConsul(this IServiceCollection services)
{
services.ConfigureByName<ConsulRegistratorOptions>();
services.AddTransient<ConsulInitializer>();
}
services.ConfigureByName<ConsulRegistratorOptions>();
services.AddHostedService<ConsulHostedService>();
services.AddSingleton<ConsulRegistrator>();
}
}
31 changes: 31 additions & 0 deletions ATI.Services.Consul/ConsulHostedService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ATI.Services.Common.Behaviors;
using JetBrains.Annotations;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

namespace ATI.Services.Consul;

[PublicAPI]
public class ConsulHostedService(
IOptions<ConsulRegistratorOptions> consulRegistratorOptions,
ConsulRegistrator registrator) : IHostedService
{
public Task StartAsync(CancellationToken ct)
{
if (!bool.TryParse(ConfigurationManager.AppSettings("ConsulEnabled"), out var enabled) || !enabled)
return Task.CompletedTask;

Console.WriteLine("ConsulHostedService is starting.");
return registrator.RegisterServicesAsync(consulRegistratorOptions.Value,
ConfigurationManager.GetApplicationPort());
}

public Task StopAsync(CancellationToken ct)
{
Console.WriteLine("ConsulHostedService is stopping.");
return registrator.DeregisterInstanceAsync();
}
}
47 changes: 0 additions & 47 deletions ATI.Services.Consul/ConsulInitializer.cs

This file was deleted.

138 changes: 69 additions & 69 deletions ATI.Services.Consul/ConsulRegistrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,93 +7,93 @@
using Newtonsoft.Json;
using NLog;

namespace ATI.Services.Consul
namespace ATI.Services.Consul;

public class ConsulRegistrator
{
public static class ConsulRegistrator
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private Timer _reregistrationTimer;
private readonly HashSet<string> _registeredServices = [];

public async Task RegisterServicesAsync(ConsulRegistratorOptions consulRegistratorOptions, int applicationPort)
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static Timer _reregistrationTimer;
private static HashSet<string> RegisteredServices { get; set; } = new();
foreach (var consulServiceOptions in consulRegistratorOptions.ConsulServiceOptions)
{
consulServiceOptions.Check.HTTP = $"http://localhost:{applicationPort}{consulServiceOptions.Check.HTTP}";
await DeregisterFromConsulAsync($"{consulServiceOptions.ServiceName}-{Dns.GetHostName()}-{applicationPort}");
}

public static async Task RegisterServicesAsync(ConsulRegistratorOptions consulRegistratorOptions, int applicationPort)
if(_reregistrationTimer != null)
await _reregistrationTimer.DisposeAsync();

_reregistrationTimer = new Timer(async _ => await RegisterServicesAsyncPrivate(consulRegistratorOptions, applicationPort),
null,
TimeSpan.FromSeconds(0),
consulRegistratorOptions.ReregistrationPeriod);
}

private async Task RegisterServicesAsyncPrivate(ConsulRegistratorOptions consulRegistratorOptions, int applicationPort)
{
try
{
foreach (var consulServiceOptions in consulRegistratorOptions.ConsulServiceOptions)
{
consulServiceOptions.Check.HTTP = $"http://localhost:{applicationPort}{consulServiceOptions.Check.HTTP}";
await DeregisterFromConsulAsync($"{consulServiceOptions.ServiceName}-{Dns.GetHostName()}-{applicationPort}");
}

_reregistrationTimer = new Timer(async _ => await RegisterServicesAsyncPrivate(consulRegistratorOptions, applicationPort),
null,
TimeSpan.FromSeconds(0),
consulRegistratorOptions.ReregistrationPeriod);
await RegisterToConsulAsync(consulServiceOptions, applicationPort);
}

private static async Task RegisterServicesAsyncPrivate(ConsulRegistratorOptions consulRegistratorOptions, int applicationPort)
catch (Exception e)
{
try
{
foreach (var consulServiceOptions in consulRegistratorOptions.ConsulServiceOptions)
await RegisterToConsulAsync(consulServiceOptions, applicationPort);
}
catch (Exception e)
{
Logger.Error(e);
}
_logger.Error(e);
}
}

private static async Task RegisterToConsulAsync(ConsulServiceOptions options, int applicationPort)
{
var serviceId = $"{options.ServiceName}-{Dns.GetHostName()}-{applicationPort}";
RegisteredServices.Add(serviceId);
private async Task RegisterToConsulAsync(ConsulServiceOptions options, int applicationPort)
{
var serviceId = $"{options.ServiceName}-{Dns.GetHostName()}-{applicationPort}";
_registeredServices.Add(serviceId);

var swaggerUrls = JsonConvert.SerializeObject(options.SwaggerUrls);
var swaggerUrls = JsonConvert.SerializeObject(options.SwaggerUrls);

using var client = new ConsulClient();
var cr = new AgentServiceRegistration
{
Name = options.ServiceName,
ID = serviceId,
Tags = options.Tags,
Check = options.Check,
Port = applicationPort,
Meta = new Dictionary<string, string>
{
{"swagger_urls", swaggerUrls}
}
};
await client.Agent.ServiceRegister(cr);
}

public static async Task DeregisterInstanceAsync()
using var client = new ConsulClient();
var cr = new AgentServiceRegistration
{
await _reregistrationTimer.DisposeAsync();
try
{
foreach (var serviceId in RegisteredServices)
{
await DeregisterFromConsulAsync(serviceId);
}
}
catch (Exception e)
Name = options.ServiceName,
ID = serviceId,
Tags = options.Tags,
Check = options.Check,
Port = applicationPort,
Meta = new Dictionary<string, string>
{
Logger.Error(e);
{"swagger_urls", swaggerUrls}
}
}
};
await client.Agent.ServiceRegister(cr);
}

private static async Task DeregisterFromConsulAsync(string serviceId)
public async Task DeregisterInstanceAsync()
{
await _reregistrationTimer.DisposeAsync();
try
{
try
{
using var client = new ConsulClient();
await client.Agent.ServiceDeregister(serviceId);
}
catch (Exception ex)
foreach (var serviceId in _registeredServices)
{
Logger.Error(ex, $"Не удалось дерегистрировать {serviceId} из консула.");
await DeregisterFromConsulAsync(serviceId);
}
}
catch (Exception e)
{
_logger.Error(e);
}
}


private async Task DeregisterFromConsulAsync(string serviceId)
{
try
{
using var client = new ConsulClient();
await client.Agent.ServiceDeregister(serviceId);
}
catch (Exception ex)
{
_logger.Error(ex, $"Не удалось дерегистрировать {serviceId} из консула.");
}
}
}
}

0 comments on commit 972a306

Please sign in to comment.