Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions src/Ocelot.Provider.Consul/ConsulFileConfigurationRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,28 @@ public ConsulFileConfigurationRepository(
_consul = factory.Get(config);
}

public async Task<Response<FileConfiguration>> Get()
public async Task<FileConfiguration> GetAsync()
{
var config = _cache.Get(_configurationKey, _configurationKey);
if (config != null)
{
return new OkResponse<FileConfiguration>(config);
return config;
}

var queryResult = await _consul.KV.Get(_configurationKey);
if (queryResult.Response == null)
{
return new OkResponse<FileConfiguration>(null);
return null;
}

var bytes = queryResult.Response.Value;
var json = Encoding.UTF8.GetString(bytes);
var consulConfig = JsonConvert.DeserializeObject<FileConfiguration>(json);

return new OkResponse<FileConfiguration>(consulConfig);
return consulConfig;
}

public async Task<Response> Set(FileConfiguration ocelotConfiguration)
public async Task SetAsync(FileConfiguration ocelotConfiguration)
{
var json = JsonConvert.SerializeObject(ocelotConfiguration, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
Expand All @@ -68,13 +68,12 @@ public async Task<Response> Set(FileConfiguration ocelotConfiguration)
};

var result = await _consul.KV.Put(kvPair);
if (result.Response)
if (!result.Response)
{
_cache.AddOrUpdate(_configurationKey, ocelotConfiguration, _configurationKey, TimeSpan.FromSeconds(3));
return new OkResponse();
throw new UnableToSetConfigInConsulException(
$"Unable to set {nameof(FileConfiguration)} in {nameof(Consul)}! Response status code from {nameof(Consul)} was {result.StatusCode} being returned in {result.RequestTime.TotalMilliseconds} ms.");
}

return new ErrorResponse(new UnableToSetConfigInConsulError(
$"Unable to set {nameof(FileConfiguration)} in {nameof(Consul)}, response status code from {nameof(Consul)} was {result.StatusCode}"));
_cache.AddOrUpdate(_configurationKey, ocelotConfiguration, _configurationKey, TimeSpan.FromSeconds(3));
}
}
62 changes: 34 additions & 28 deletions src/Ocelot.Provider.Consul/ConsulMiddlewareConfigurationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,48 +34,54 @@ private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
IFileConfigurationRepository fileConfigRepo, IOptionsMonitor<FileConfiguration> fileConfig,
IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
{
// Get the config from Consul
var fileConfigFromConsul = await fileConfigRepo.Get();
if (IsError(fileConfigFromConsul))
try
{
ThrowToStopOcelotStarting(fileConfigFromConsul);
}
else if (ConfigNotStoredInConsul(fileConfigFromConsul))
{
// there was no config in Consul set the file in config in Consul
await fileConfigRepo.Set(fileConfig.CurrentValue);
}
else
{
// Create the internal config from Consul data
var internalConfig = await internalConfigCreator.Create(fileConfigFromConsul.Data);
if (IsError(internalConfig))
// Get the config from Consul
var fileConfigFromConsul = await fileConfigRepo.GetAsync();
if (fileConfigFromConsul == null)
{
ThrowToStopOcelotStarting(internalConfig);
// there was no config in Consul set the file in config in Consul
await fileConfigRepo.SetAsync(fileConfig.CurrentValue);
}
else
{
// add the internal config to the internal repo
var response = internalConfigRepo.AddOrReplace(internalConfig.Data);
if (IsError(response))
// Create the internal config from Consul data
var internalConfig = await internalConfigCreator.Create(fileConfigFromConsul);
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(response);
ThrowToStopOcelotStarting(internalConfig);
}
else
{
// add the internal config to the internal repo
var response = internalConfigRepo.AddOrReplace(internalConfig.Data);
if (IsError(response))
{
ThrowToStopOcelotStarting(response);
}
}
}

if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
}
}
}
catch (Exception ex)
{
ThrowToStopOcelotStarting(ex); // performance issue?
}
}

private static void ThrowToStopOcelotStarting(Response config)
=> throw new Exception($"Unable to start Ocelot, errors are:{config.Errors.ToErrorString(true, true)}");
=> throw NewException(string.Join(',', config.Errors.Select(x => x.ToString())));

private static void ThrowToStopOcelotStarting(Exception ex)
=> throw NewException(ex.GetMessages());

private static Exception NewException(string errors)
=> new($"Unable to start Ocelot! Errors are:{Environment.NewLine}{errors}");

private static bool IsError(Response response)
=> response == null || response.IsError;

private static bool ConfigNotStoredInConsul(Response<FileConfiguration> fileConfigFromConsul)
=> fileConfigFromConsul.Data == null;
}
12 changes: 0 additions & 12 deletions src/Ocelot.Provider.Consul/UnableToSetConfigInConsulError.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Ocelot.Provider.Consul;

public class UnableToSetConfigInConsulException : Exception
{
public UnableToSetConfigInConsulException(string message)
: base(message) { }
}
26 changes: 14 additions & 12 deletions src/Ocelot/Administration/FileConfigurationController.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Ocelot.Configuration;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Configuration.Setter;
using Ocelot.Infrastructure.Extensions;

namespace Ocelot.Administration;

Expand All @@ -22,35 +24,35 @@ public FileConfigurationController(IFileConfigurationRepository repo, IFileConfi
}

[HttpGet]
public async Task<IActionResult> Get()
public async Task<ActionResult> Get()
{
var response = await _repo.Get();

if (response.IsError)
try
{
return new BadRequestObjectResult(response.Errors);
var fileConfiguration = await _repo.GetAsync();
return Ok(fileConfiguration);
}
catch (Exception ex)
{
return BadRequest(ex.GetMessages());
}

return new OkObjectResult(response.Data);
}

[HttpPost]
public async Task<IActionResult> Post([FromBody] FileConfiguration fileConfiguration)
public async Task<ActionResult> Post([FromBody] FileConfiguration fileConfiguration)
{
try
{
var response = await _setter.Set(fileConfiguration);

if (response.IsError)
{
return new BadRequestObjectResult(response.Errors);
return BadRequest(response.Errors);
}

return new OkObjectResult(fileConfiguration);
return Ok(fileConfiguration);
}
catch (Exception e)
{
return new BadRequestObjectResult($"{e.Message}:{Environment.NewLine}{e.StackTrace}");
return BadRequest($"{e.Message}:{Environment.NewLine}{e.StackTrace}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,33 @@ public ConsulFileConfigurationPollerOption(IInternalConfigurationRepository inte
_fileConfigurationRepository = fileConfigurationRepository;
}

public int Delay => GetDelay();
public int Delay => GetDelay().GetAwaiter().GetResult();

private int GetDelay()
{
var delay = 1000;

var fileConfig = _fileConfigurationRepository.Get().GetAwaiter().GetResult(); // sync call, so TODO extend IFileConfigurationPollerOptions interface with 2nd async method
if (fileConfig?.Data?.GlobalConfiguration?.ServiceDiscoveryProvider != null &&
!fileConfig.IsError &&
fileConfig.Data.GlobalConfiguration.ServiceDiscoveryProvider.PollingInterval > 0)
{
delay = fileConfig.Data.GlobalConfiguration.ServiceDiscoveryProvider.PollingInterval;
}
else
private async Task<int> GetDelay()
{
var internalConfig = _internalConfigRepo.Get();
if (internalConfig?.Data?.ServiceProviderConfiguration != null &&
!internalConfig.IsError &&
internalConfig.Data.ServiceProviderConfiguration.PollingInterval > 0)
var delay = 1000;
try
{
var fileConfig = await _fileConfigurationRepository.GetAsync();
var provider = fileConfig?.GlobalConfiguration?.ServiceDiscoveryProvider;
if (provider != null && provider.PollingInterval > 0)
{
delay = provider.PollingInterval;
}
else
{
var internalConfig = _internalConfigRepo.Get();
var configuration = internalConfig?.Data?.ServiceProviderConfiguration;
if (configuration != null && configuration.PollingInterval > 0)
{
delay = configuration.PollingInterval;
}
}
}
catch
{
delay = internalConfig.Data.ServiceProviderConfiguration.PollingInterval;
delay = 0;
}
}

return delay;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private void Initialize(string folder)
_environmentFile = new FileInfo(Path.Combine(folder, envFile));
}

public Task<Response<FileConfiguration>> Get()
public Task<FileConfiguration> GetAsync()
{
string jsonConfiguration;

Expand All @@ -50,11 +50,10 @@ public Task<Response<FileConfiguration>> Get()
}

var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(jsonConfiguration);

return Task.FromResult<Response<FileConfiguration>>(new OkResponse<FileConfiguration>(fileConfiguration));
return Task.FromResult(fileConfiguration);
}

public Task<Response> Set(FileConfiguration fileConfiguration)
public Task SetAsync(FileConfiguration fileConfiguration)
{
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented);

Expand All @@ -76,6 +75,6 @@ public Task<Response> Set(FileConfiguration fileConfiguration)
}

_changeTokenSource.Activate();
return Task.FromResult<Response>(new OkResponse());
return Task.CompletedTask;
}
}
53 changes: 24 additions & 29 deletions src/Ocelot/Configuration/Repository/FileConfigurationPoller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Logging;
using Ocelot.Infrastructure.Extensions;

namespace Ocelot.Configuration.Repository;

public class FileConfigurationPoller : IHostedService, IDisposable
public sealed class FileConfigurationPoller : IHostedService, IDisposable
{
private readonly IOcelotLogger _logger;
private readonly IFileConfigurationRepository _repo;
Expand Down Expand Up @@ -62,46 +63,40 @@ public Task StopAsync(CancellationToken cancellationToken)

private async Task Poll()
{
_logger.LogInformation("Started polling");

var fileConfig = await _repo.Get();
_logger.LogInformation($"Started {nameof(Poll)}ing");
try
{
var fileConfig = await _repo.GetAsync();
var asJson = ToJson(fileConfig);
if (asJson != _previousAsJson)
{
var config = await _internalConfigCreator.Create(fileConfig);
if (!config.IsError)
{
_internalConfigRepo.AddOrReplace(config.Data);
}

if (fileConfig.IsError)
_previousAsJson = asJson;
}
}
catch (Exception ex)
{
_logger.LogWarning(() => $"error geting file config, errors are {string.Join(',', fileConfig.Errors.Select(x => x.Message))}");
return;
_logger.LogWarning($"Error getting file config! Errors are:{Environment.NewLine}{ex.AllMessages}");
}

var asJson = ToJson(fileConfig.Data);

if (!fileConfig.IsError && asJson != _previousAsJson)
finally
{
var config = await _internalConfigCreator.Create(fileConfig.Data);

if (!config.IsError)
{
_internalConfigRepo.AddOrReplace(config.Data);
}

_previousAsJson = asJson;
_logger.LogInformation($"Finished {nameof(Poll)}ing");
}

_logger.LogInformation("Finished polling");
}

/// <summary>
/// We could do object comparison here but performance isnt really a problem. This might be an issue one day!.
/// We could do object comparison here but performance isnt really a problem. This might be an issue one day.
/// </summary>
/// <returns>hash of the config.</returns>
private static string ToJson(FileConfiguration config)
{
var currentHash = JsonConvert.SerializeObject(config);
return currentHash;
}
/// <returns>A <see langword="string"/> with current hash of the config.</returns>
private static string ToJson(FileConfiguration config) => JsonConvert.SerializeObject(config);

public void Dispose()
{
_timer?.Dispose();
_timer = null;
}
}
Loading
Loading