mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 18:22:49 +08:00
Made the file config poller use IHostedService, bit more generic, not… (#507)
* Made the file config poller use IHostedService, bit more generic, not just need to provide the correct implementations of the repo services and it will poll anything..this means we can open up redis for #458 * removed comments
This commit is contained in:
parent
1817564ea5
commit
0f2cf2d188
@ -2,34 +2,45 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Setter;
|
using Ocelot.Configuration.Setter;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Repository
|
namespace Ocelot.Configuration.Repository
|
||||||
{
|
{
|
||||||
public class ConsulFileConfigurationPoller : IDisposable
|
public class FileConfigurationPoller : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IOcelotLogger _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
private readonly IFileConfigurationRepository _repo;
|
private readonly IFileConfigurationRepository _repo;
|
||||||
private readonly IFileConfigurationSetter _setter;
|
|
||||||
private string _previousAsJson;
|
private string _previousAsJson;
|
||||||
private readonly Timer _timer;
|
private Timer _timer;
|
||||||
private bool _polling;
|
private bool _polling;
|
||||||
private readonly IConsulPollerConfiguration _config;
|
private readonly IFileConfigurationPollerOptions _options;
|
||||||
|
private readonly IInternalConfigurationRepository _internalConfigRepo;
|
||||||
|
private readonly IInternalConfigurationCreator _internalConfigCreator;
|
||||||
|
|
||||||
public ConsulFileConfigurationPoller(
|
public FileConfigurationPoller(
|
||||||
IOcelotLoggerFactory factory,
|
IOcelotLoggerFactory factory,
|
||||||
IFileConfigurationRepository repo,
|
IFileConfigurationRepository repo,
|
||||||
IFileConfigurationSetter setter,
|
IFileConfigurationPollerOptions options,
|
||||||
IConsulPollerConfiguration config)
|
IInternalConfigurationRepository internalConfigRepo,
|
||||||
|
IInternalConfigurationCreator internalConfigCreator)
|
||||||
{
|
{
|
||||||
_setter = setter;
|
_internalConfigRepo = internalConfigRepo;
|
||||||
_config = config;
|
_internalConfigCreator = internalConfigCreator;
|
||||||
_logger = factory.CreateLogger<ConsulFileConfigurationPoller>();
|
_options = options;
|
||||||
|
_logger = factory.CreateLogger<FileConfigurationPoller>();
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_previousAsJson = "";
|
_previousAsJson = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"{nameof(FileConfigurationPoller)} is starting.");
|
||||||
|
|
||||||
_timer = new Timer(async x =>
|
_timer = new Timer(async x =>
|
||||||
{
|
{
|
||||||
if(_polling)
|
if(_polling)
|
||||||
@ -40,7 +51,18 @@ namespace Ocelot.Configuration.Repository
|
|||||||
_polling = true;
|
_polling = true;
|
||||||
await Poll();
|
await Poll();
|
||||||
_polling = false;
|
_polling = false;
|
||||||
}, null, _config.Delay, _config.Delay);
|
}, null, _options.Delay, _options.Delay);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"{nameof(FileConfigurationPoller)} is stopping.");
|
||||||
|
|
||||||
|
_timer?.Change(Timeout.Infinite, 0);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Poll()
|
private async Task Poll()
|
||||||
@ -59,7 +81,13 @@ namespace Ocelot.Configuration.Repository
|
|||||||
|
|
||||||
if(!fileConfig.IsError && asJson != _previousAsJson)
|
if(!fileConfig.IsError && asJson != _previousAsJson)
|
||||||
{
|
{
|
||||||
await _setter.Set(fileConfig.Data);
|
var config = await _internalConfigCreator.Create(fileConfig.Data);
|
||||||
|
|
||||||
|
if(!config.IsError)
|
||||||
|
{
|
||||||
|
_internalConfigRepo.AddOrReplace(config.Data);
|
||||||
|
}
|
||||||
|
|
||||||
_previousAsJson = asJson;
|
_previousAsJson = asJson;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.Repository
|
namespace Ocelot.Configuration.Repository
|
||||||
{
|
{
|
||||||
public interface IConsulPollerConfiguration
|
public interface IFileConfigurationPollerOptions
|
||||||
{
|
{
|
||||||
int Delay { get; }
|
int Delay { get; }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.Repository
|
namespace Ocelot.Configuration.Repository
|
||||||
{
|
{
|
||||||
public class InMemoryConsulPollerConfiguration : IConsulPollerConfiguration
|
public class InMemoryFileConfigurationPollerOptions : IFileConfigurationPollerOptions
|
||||||
{
|
{
|
||||||
public int Delay => 1000;
|
public int Delay => 1000;
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ namespace Ocelot.Configuration.Setter
|
|||||||
{
|
{
|
||||||
public class FileAndInternalConfigurationSetter : IFileConfigurationSetter
|
public class FileAndInternalConfigurationSetter : IFileConfigurationSetter
|
||||||
{
|
{
|
||||||
private readonly IInternalConfigurationRepository _configRepo;
|
private readonly IInternalConfigurationRepository internalConfigRepo;
|
||||||
private readonly IInternalConfigurationCreator _configCreator;
|
private readonly IInternalConfigurationCreator _configCreator;
|
||||||
private readonly IFileConfigurationRepository _repo;
|
private readonly IFileConfigurationRepository _repo;
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace Ocelot.Configuration.Setter
|
|||||||
IInternalConfigurationCreator configCreator,
|
IInternalConfigurationCreator configCreator,
|
||||||
IFileConfigurationRepository repo)
|
IFileConfigurationRepository repo)
|
||||||
{
|
{
|
||||||
_configRepo = configRepo;
|
internalConfigRepo = configRepo;
|
||||||
_configCreator = configCreator;
|
_configCreator = configCreator;
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ namespace Ocelot.Configuration.Setter
|
|||||||
|
|
||||||
if(!config.IsError)
|
if(!config.IsError)
|
||||||
{
|
{
|
||||||
_configRepo.AddOrReplace(config.Data);
|
internalConfigRepo.AddOrReplace(config.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ErrorResponse(config.Errors);
|
return new ErrorResponse(config.Errors);
|
||||||
|
@ -160,7 +160,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
|
|
||||||
// We add this here so that we can always inject something into the factory for IoC..
|
// We add this here so that we can always inject something into the factory for IoC..
|
||||||
_services.AddSingleton<IServiceTracer, FakeServiceTracer>();
|
_services.AddSingleton<IServiceTracer, FakeServiceTracer>();
|
||||||
_services.TryAddSingleton<IConsulPollerConfiguration, InMemoryConsulPollerConfiguration>();
|
_services.TryAddSingleton<IFileConfigurationPollerOptions, InMemoryFileConfigurationPollerOptions>();
|
||||||
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
|
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
|
||||||
_services.TryAddSingleton<IPlaceholders, Placeholders>();
|
_services.TryAddSingleton<IPlaceholders, Placeholders>();
|
||||||
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
||||||
@ -245,7 +245,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
|
|
||||||
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
|
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
|
||||||
{
|
{
|
||||||
_services.AddSingleton<ConsulFileConfigurationPoller>();
|
_services.AddHostedService<FileConfigurationPoller>();
|
||||||
_services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
|
_services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -183,9 +183,6 @@
|
|||||||
ThrowToStopOcelotStarting(internalConfig);
|
ThrowToStopOcelotStarting(internalConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo - this starts the poller if it has been registered...please this is so bad.
|
|
||||||
var hack = builder.ApplicationServices.GetService(typeof(ConsulFileConfigurationPoller));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptions<FileConfiguration> fileConfig)
|
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptions<FileConfiguration> fileConfig)
|
||||||
|
@ -122,6 +122,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
public void should_load_configuration_out_of_consul()
|
public void should_load_configuration_out_of_consul()
|
||||||
{
|
{
|
||||||
var consulPort = 8500;
|
var consulPort = 8500;
|
||||||
|
|
||||||
var configuration = new FileConfiguration
|
var configuration = new FileConfiguration
|
||||||
{
|
{
|
||||||
GlobalConfiguration = new FileGlobalConfiguration()
|
GlobalConfiguration = new FileGlobalConfiguration()
|
||||||
|
@ -12,35 +12,37 @@ using TestStack.BDDfy;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using static Ocelot.Infrastructure.Wait;
|
using static Ocelot.Infrastructure.Wait;
|
||||||
|
using Ocelot.Configuration.Creator;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Configuration
|
namespace Ocelot.UnitTests.Configuration
|
||||||
{
|
{
|
||||||
public class ConsulFileConfigurationPollerTests : IDisposable
|
public class FileConfigurationPollerTests : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ConsulFileConfigurationPoller _poller;
|
private readonly FileConfigurationPoller _poller;
|
||||||
private Mock<IOcelotLoggerFactory> _factory;
|
private Mock<IOcelotLoggerFactory> _factory;
|
||||||
private readonly Mock<IFileConfigurationRepository> _repo;
|
private readonly Mock<IFileConfigurationRepository> _repo;
|
||||||
private readonly Mock<IFileConfigurationSetter> _setter;
|
|
||||||
private readonly FileConfiguration _fileConfig;
|
private readonly FileConfiguration _fileConfig;
|
||||||
private Mock<IConsulPollerConfiguration> _config;
|
private Mock<IFileConfigurationPollerOptions> _config;
|
||||||
|
private readonly Mock<IInternalConfigurationRepository> _internalConfigRepo;
|
||||||
|
private readonly Mock<IInternalConfigurationCreator> _internalConfigCreator;
|
||||||
|
private IInternalConfiguration _internalConfig;
|
||||||
|
|
||||||
public ConsulFileConfigurationPollerTests()
|
public FileConfigurationPollerTests()
|
||||||
{
|
{
|
||||||
var logger = new Mock<IOcelotLogger>();
|
var logger = new Mock<IOcelotLogger>();
|
||||||
_factory = new Mock<IOcelotLoggerFactory>();
|
_factory = new Mock<IOcelotLoggerFactory>();
|
||||||
_factory.Setup(x => x.CreateLogger<ConsulFileConfigurationPoller>()).Returns(logger.Object);
|
_factory.Setup(x => x.CreateLogger<FileConfigurationPoller>()).Returns(logger.Object);
|
||||||
_repo = new Mock<IFileConfigurationRepository>();
|
_repo = new Mock<IFileConfigurationRepository>();
|
||||||
_setter = new Mock<IFileConfigurationSetter>();
|
|
||||||
_fileConfig = new FileConfiguration();
|
_fileConfig = new FileConfiguration();
|
||||||
_config = new Mock<IConsulPollerConfiguration>();
|
_config = new Mock<IFileConfigurationPollerOptions>();
|
||||||
_repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
|
_repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
|
||||||
_config.Setup(x => x.Delay).Returns(100);
|
_config.Setup(x => x.Delay).Returns(100);
|
||||||
_poller = new ConsulFileConfigurationPoller(_factory.Object, _repo.Object, _setter.Object, _config.Object);
|
_internalConfigRepo = new Mock<IInternalConfigurationRepository>();
|
||||||
}
|
_internalConfigCreator = new Mock<IInternalConfigurationCreator>();
|
||||||
|
_internalConfigCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).ReturnsAsync(new OkResponse<IInternalConfiguration>(_internalConfig));
|
||||||
public void Dispose()
|
_poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object);
|
||||||
{
|
_poller.StartAsync(new CancellationToken());
|
||||||
_poller.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -141,10 +143,11 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
|
private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
|
||||||
{
|
{
|
||||||
var result = WaitFor(2000).Until(() => {
|
var result = WaitFor(4000).Until(() => {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_setter.Verify(x => x.Set(fileConfig), Times.Exactly(times));
|
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.Exactly(times));
|
||||||
|
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.Exactly(times));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch(Exception)
|
||||||
@ -157,10 +160,11 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
private void ThenTheSetterIsCalledAtLeast(FileConfiguration fileConfig, int times)
|
private void ThenTheSetterIsCalledAtLeast(FileConfiguration fileConfig, int times)
|
||||||
{
|
{
|
||||||
var result = WaitFor(2000).Until(() => {
|
var result = WaitFor(4000).Until(() => {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_setter.Verify(x => x.Set(fileConfig), Times.AtLeast(times));
|
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.AtLeast(times));
|
||||||
|
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.AtLeast(times));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch(Exception)
|
||||||
@ -170,5 +174,10 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
});
|
});
|
||||||
result.ShouldBeTrue();
|
result.ShouldBeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_poller.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user