Служба не регистрируется в Консуле при запуске из IIS - PullRequest
0 голосов
/ 17 сентября 2018

Я использую микросервис ASP.NET Core под IIS 10.0 и пытаюсь зарегистрировать его в Консуле при запуске.Я добавил следующий код в Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    services.AddSingleton<IHostedService, ConsulHostedService>();
    services.Configure<ConsulConfig>(Configuration.GetSection("consulConfig"));
    services.AddSingleton<IConsulClient>(p => new ConsulClient(ConfigOverride));
}

private void ConfigOverride(ConsulClientConfiguration config)
{
    var address = Configuration["ConsulConfig:ConsulAddress"];
    config.Address = new Uri(address);
}

Это прекрасно работает при запуске в качестве отдельного проекта, но при запуске в IIS служба не регистрируется сама по себе, пока я не нажму "Обзор", По словам Сезара де ла Торре , ConsulHostedService.Startup следует вызывать во время запуска приложения, но, похоже, этого не происходит.

Учитывая тот факт, что это не кажетсяпроблема, возникающая при работе в автономном режиме, похоже, это проблема IIS, но я не могу понять, какие, в частности, настройки, которые мне нужно переключить.Единственное, что мне показалось связанным, было «Preload Enabled» в расширенных настройках сайта, но безуспешно.

Если в моем коде что-то отсутствует, вот полный класс Startup:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        services.AddSingleton<IHostedService, ConsulHostedService>();
        services.Configure<ConsulConfig>(Configuration.GetSection("consulConfig"));
        services.AddSingleton<IConsulClient>(p => new ConsulClient(ConfigOverride));
    }

    private void ConfigOverride(ConsulClientConfiguration config)
    {
        var address = Configuration["ConsulConfig:ConsulAddress"];
        config.Address = new Uri(address);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
            app.UseDeveloperExceptionPage();
        else
            app.UseHsts();
        app.UseMvc();
    }
}

И ConsulHostedService:

public class ConsulHostedService : IHostedService
{
    private CancellationTokenSource _cts;
    private readonly IConsulClient _consulClient;
    private readonly IOptions<ConsulConfig> _consulConfig;
    private readonly ILogger<ConsulHostedService> _logger;
    private readonly IServer _server;
    private string _registrationId;

    public ConsulHostedService(IConsulClient consulClient, IOptions<ConsulConfig> consulConfig,
        ILogger<ConsulHostedService> logger, IServer server)
    {
        _consulClient = consulClient;
        _consulConfig = consulConfig;
        _logger = logger;
        _server = server;
    }

    public async Task StartAsync(CancellationToken token)
    {
        _cts = CancellationTokenSource.CreateLinkedTokenSource(token);
        var uri = GetServerAddress();
        _registrationId = $"{_consulConfig.Value.ServiceId}-{_consulConfig.Value.ServicePort}";
        AgentServiceRegistration registration = MakeConsulRegistration(uri);
        await Register(registration);
    }

    private Uri GetServerAddress()
    {
        var features = _server.Features;
        var addresses = features.Get<IServerAddressesFeature>();
        var address = addresses.Addresses.First();
        return new Uri(address);
    }

    private AgentServiceRegistration MakeConsulRegistration(Uri uri)
    {
        return new AgentServiceRegistration()
        {
            ID = _registrationId,
            Name = _consulConfig.Value.ServiceName,
            Address = $"http://localhost",
            Port = _consulConfig.Value.ServicePort,
            Tags = _consulConfig.Value.ServiceTags,
            Check = MakeConsulCheck(uri)
        };
    }

    private AgentServiceCheck MakeConsulCheck(Uri uri)
    {
        return new AgentServiceCheck()
        {
            HTTP = $"http://localhost:{_consulConfig.Value.ServicePort}/api/meta/status",
            Timeout = TimeSpan.FromSeconds(3),
            Interval = TimeSpan.FromSeconds(10)
        };
    }

    private async Task Register(AgentServiceRegistration registration)
    {
        _logger.LogInformation("Registering in Consul");
        await _consulClient.Agent.ServiceDeregister(registration.ID, _cts.Token);
        await _consulClient.Agent.ServiceRegister(registration, _cts.Token);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _cts.Cancel();
        _logger.LogInformation("Deregistering from Consul");
        try
        {
            await _consulClient.Agent.ServiceDeregister(_registrationId, cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Deregistration failed");
        }
    }
}

1 Ответ

0 голосов
/ 17 сентября 2018

Для warm up вашего микросервиса, вы можете установить Start Mode на AlwaysRunning.Детали режима: Как получить немедленный запуск веб-сайта .Net Core, размещенного в IIS?

Но похоже, что вам нужно позаботиться о first request какпоследний этап процесса развертывания , поскольку вы упомянули, что «естественные запросы» от клиентов могут использоваться как warm up.

Примечания: в общем случае ConfigureServices и Configure называютсяпо времени выполнения, когда приложение запускается в соответствии с документацией .Вы также можете попытаться обойти эту проблему, настроив свой микросервис без класса Startup - через HostBuilder (аналогично WebHostBuilder) - проверьте Использование HostBuilder и универсального хоста в .NET Core Microservices .Также взгляните на IHostedService подход, который может лучше соответствовать вашим потребностям: Реализация IHostedService в ASP.NET Core 2.0

...