Как я могу создать сервис BackGround, который запускает функцию каждый заданный период времени? Использование C# (asp. net core 3.1.1) - PullRequest
1 голос
/ 24 марта 2020

Я пытаюсь вызывать функцию через каждый указанный интервал времени, для этого m, используя Фоновую службу, вот что я сделал: Вот контроллер предупреждений, где у меня есть функция:

public class AlertingController : ControllerBase
{
    private readonly DatabaseContext _context;
    private readonly IMapper _mapper;

    public AlertingController(DatabaseContext context, IMapper mapper)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
    }
    public AlertingController()
    {

    }
//function that adds in the DB
    public async Task<AlertingResponse> GetAlertingToDB()
    {
        AlertingResponse dataGet;

        using (var httpClient = new HttpClient())
        {
            using (var response = await httpClient
                .GetAsync(MetricApiLink))
            {
                string apiResponse = await response.Content.ReadAsStringAsync();
                dataGet = JsonConvert.DeserializeObject<AlertingResponse>(apiResponse);
            }
        }
        if (dataGet.data.alerts != null || dataGet.data.alerts.Count > 0)
        {
            foreach (var alert in dataGet.data.alerts)
            {
                CreateAlertQuery QueryAlert = new CreateAlertQuery();
                QueryAlert.Name = alert.labels.alertname;
                QueryAlert.Instance = alert.labels.instance;
                QueryAlert.Serverity = alert.labels.severity;
                QueryAlert.Summary = alert.annotations.summary;
                QueryAlert.State = alert.state;
                QueryAlert.ActiveAt = alert.activeAt;
                var _Alert = _mapper.Map<AlertingDataModel>(QueryAlert);
                _context.Alertings.Add(_Alert);
                await _context.SaveChangesAsync();
            }
        }

        return null;
    }
}

Я протестировал метод с запросом HTTPGET, он работает нормально, добавьте предупреждения в мою базу данных:

enter image description here

Я создал scooped сервис, в котором я вызвал функцию GetAlertingToDB():

    internal interface IScopedAlertingService
    {
        Task DoWork(CancellationToken stoppingToken);
    }
    public class ScopedAlertingService : IScopedAlertingService
    {
        private int executionCount = 0;
        private readonly ILogger _logger;

    public ScopedAlertingService(ILogger<ScopedAlertingService> logger)
    {
        _logger = logger;
    }

    public async Task DoWork(CancellationToken stoppingToken)
    {
        AlertingController _AlertingToDB = new AlertingController();
        while (!stoppingToken.IsCancellationRequested)
        {
            executionCount++;

            _logger.LogInformation(
                "Scoped Processing Service is working. Count: {Count}", executionCount);

            await _AlertingToDB.GetAlertingToDB();

            await Task.Delay(10000, stoppingToken);
        }
    }
}

Я также создал класс, который будет использовать мой сервис, и будет работать в BackGround:

public class ConsumeScopedServiceHostedService : BackgroundService
{
    private readonly ILogger<ConsumeScopedServiceHostedService> _logger;

    public ConsumeScopedServiceHostedService(IServiceProvider services,
        ILogger<ConsumeScopedServiceHostedService> logger)
    {
        Services = services;
        _logger = logger;
    }

    public IServiceProvider Services { get; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service running.");

        await DoWork(stoppingToken);
    }

    private async Task DoWork(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is working.");

        using (var scope = Services.CreateScope())
        {
            var scopedProcessingService =
                scope.ServiceProvider
                    .GetRequiredService<IScopedAlertingService>();

            await scopedProcessingService.DoWork(stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Consume Scoped Service Hosted Service is stopping.");

        await Task.CompletedTask;
    }
}

Я ввел зависимости от класса запуска и добавленной размещенной службы:

        services.AddHostedService<ConsumeScopedServiceHostedService>();
        services.AddScoped<IScopedAlertingService, ScopedAlertingService>();

Функции работают очень хорошо, пока не вызывается функция GetAlertingToDB(), и она не работает.

Любая помощь будет будь здоров, спасибо всем:)

Ответы [ 3 ]

0 голосов
/ 24 марта 2020

Для этого есть несколько вариантов.

Пожалуйста, прочитайте следующую ссылку в документации Microsoft, в которой есть несколько примеров того, как это сделать. NET Core и ASP. NET Core :

Worker Service In NET Core

Это называется Worker Services.

В основном вы реализуете два интерфейса: IHostedService, IDisposable

Затем вы регистрируете свой сервис в своем классе запуска в вашем методе ConfigureServices следующим образом:

services.AddHostedService<MyCoolWorkerServiceClass>();

Для Полный пример

Последнее предложение. В примере используется System.Threading.Timer ... Но я думаю, что лучше использовать System.Timers.Timer с AutoReset = false.

Причина заключается в том, чтобы избежать перекрывающихся запусков вашей службы. После выполнения запуска вы снова запускаете таймер.

Но опять же все зависит от того, чего вы хотите достичь.

0 голосов
/ 24 марта 2020

Лично я бы перестроил ваше решение, чтобы вашему фоновому сервису не нужно было создавать Controller. Вместо этого контроллер, если он вам все еще нужен, должен позвонить в ваш ScopedAlertingService, где работа выполняется один раз. Ваш фоновый сервис может просто l oop навсегда, с await Task.Delay().

    public class ScopedAlertingService : IScopedAlertingService
    {
        public async Task DoWork(CancellationToken stoppingToken)
        {
            // move contents of your AlertingController.GetAlertingToDB here
        }
    }

    public class ConsumeScopedServiceHostedService : BackgroundService
    {
        private readonly IServiceProvider _services;
        public ConsumeScopedServiceHostedService(IServiceProvider services)
        {
            _services = services;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(10000, stoppingToken);

                using (var scope = _services.CreateScope())
                {
                    var scopedProcessingService =
                        scope.ServiceProvider
                            .GetRequiredService<IScopedAlertingService>();

                    await scopedProcessingService.DoWork(stoppingToken);
                }
            }
        }
    }
0 голосов
/ 24 марта 2020

Hangfire RecurringJob будет вариантом для вашего случая. Вы можете проверить это здесь https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html. Преимущество его использования: у вас есть панель мониторинга, чтобы проверить, когда будет запущена задача и ее результат.

...