< Summary

Information
Class: OzonOrdersWeb.HostedServices.OrderSearchStartupHostedService
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/HostedServices/OrderSearchStartupHostedService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 46
Coverable lines: 46
Total lines: 110
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
StartAsync(...)100%210%
StopAsync(...)100%210%
RunBootstrapAsync()0%272160%
WaitForJobStorageAsync()0%620%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/HostedServices/OrderSearchStartupHostedService.cs

#LineLine coverage
 1using Hangfire;
 2using Microsoft.Extensions.Configuration;
 3using Microsoft.Extensions.DependencyInjection;
 4using Microsoft.Extensions.Hosting;
 5using Serilog;
 6using Services.SearchServices.OrderSearch;
 7
 8namespace OzonOrdersWeb.HostedServices;
 9
 10/// <summary>
 11/// При включённом OrdersSearch:UseElasticsearch создаёт индекс при первом старте
 12/// и (опционально) ставит полную переиндексацию, если индекс пуст — удобно для локальной разработки.
 13/// </summary>
 14public sealed class OrderSearchStartupHostedService : IHostedService
 15{
 16    private readonly IServiceProvider _services;
 17    private readonly IConfiguration _configuration;
 18    private readonly IHostApplicationLifetime _lifetime;
 19
 020    public OrderSearchStartupHostedService(
 021        IServiceProvider services,
 022        IConfiguration configuration,
 023        IHostApplicationLifetime lifetime)
 24    {
 025        _services = services;
 026        _configuration = configuration;
 027        _lifetime = lifetime;
 028    }
 29
 30    public Task StartAsync(CancellationToken cancellationToken)
 31    {
 032        _lifetime.ApplicationStarted.Register(() => _ = RunBootstrapAsync());
 033        return Task.CompletedTask;
 34    }
 35
 036    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
 37
 38    private async Task RunBootstrapAsync()
 39    {
 040        if (!_configuration.GetValue<bool>("OrdersSearch:UseElasticsearch"))
 41        {
 042            return;
 43        }
 44
 45        try
 46        {
 047            using var scope = _services.CreateScope();
 048            var searchService = scope.ServiceProvider.GetRequiredService<IOrderSearchService>();
 49
 50            // CreateIndexAsync идемпотентен: у существующего индекса он донастраивает mapping
 51            // (поле Scanit), поэтому вызывается всегда, а не только при создании.
 052            var indexExisted = await searchService.IndexExistsAsync();
 053            var created = await searchService.CreateIndexAsync();
 054            if (!created)
 55            {
 056                Log.Warning("OrderSearch: не удалось создать или обновить индекс — проверьте доступность Elasticsearch (
 057                    _configuration["OrdersSearch:Url"] ?? "http://localhost:9201");
 058                return;
 59            }
 60
 061            if (!indexExisted)
 62            {
 063                Log.Information("OrderSearch: индекс {Index} создан", _configuration["OrdersSearch:IndexName"] ?? "order
 64            }
 65
 066            if (!_configuration.GetValue<bool>("OrdersSearch:BootstrapReindexOnEmptyIndex"))
 67            {
 068                return;
 69            }
 70
 071            var count = await searchService.GetTotalCountAsync();
 072            if (count > 0)
 73            {
 074                return;
 75            }
 76
 077            if (!await WaitForJobStorageAsync(TimeSpan.FromSeconds(30)))
 78            {
 079                Log.Warning("OrderSearch: Hangfire JobStorage недоступен — пропуск bootstrap-переиндексации");
 080                return;
 81            }
 82
 083            BackgroundJob.Enqueue<OrderSearchFullReindexJob>(x => x.ExecuteAsync());
 084            Log.Information("OrderSearch: индекс пуст — поставлена полная переиндексация (BootstrapReindexOnEmptyIndex)"
 085        }
 086        catch (Exception ex)
 87        {
 088            Log.Warning(ex, "OrderSearch startup bootstrap failed — поиск упадёт на LIKE-fallback");
 089        }
 090    }
 91
 92    private static async Task<bool> WaitForJobStorageAsync(TimeSpan timeout)
 93    {
 094        var deadline = DateTime.UtcNow + timeout;
 095        while (DateTime.UtcNow < deadline)
 96        {
 97            try
 98            {
 099                _ = JobStorage.Current;
 0100                return true;
 101            }
 0102            catch (InvalidOperationException)
 103            {
 0104                await Task.Delay(200);
 105            }
 106        }
 107
 0108        return false;
 0109    }
 110}