PRBackgroundTaskRunner
using Microsoft.Extensions.DependencyInjection;
using PRTelegramBot.BackgroundTasks.Interfaces;
using PRTelegramBot.BackgroundTasks.Models;
using PRTelegramBot.Core;
using PRTelegramBot.EventBus;
using PRTelegramBot.EventBus.Events;
using PRTelegramBot.Extensions;
using PRTelegramBot.Models;
using PRTelegramBot.Models.EventsArgs;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace PRTelegramBot.BackgroundTasks
{
/// <summary>
/// Обработчик фоновых задач.
/// </summary>
public sealed class PRBackgroundTaskRunner : IPRBackgroundTaskRunner, IPRTaskRunnerSubscriber
{
#region Поля и свойства
/// <summary>
/// Справочник запущенных задач.
/// </summary>
private readonly ConcurrentDictionary<Guid, IRunningBackgroundTaskData> activeTasks = new();
/// <summary>
/// Завершенные задачи.
/// </summary>
private readonly HashSet<IRunningBackgroundTaskData> completedTasks = new();
/// <summary>
/// Экземпляры фоновых задач.
/// </summary>
private HashSet<IPRBackgroundTask> registeredTaskInstances = new();
/// <summary>
/// Метаданные фоновых задач.
/// </summary>
private HashSet<IPRBackgroundTaskMetadata> registeredTaskMetadata = new();
/// <summary>
/// Бот.
/// </summary>
private PRBotBase bot;
/// <summary>
/// Глобальный токен бота.
/// </summary>
private CancellationToken botToken => bot.Options.CancellationTokenSource.Token;
#endregion
#region IPRBackgroundTaskRunner
/// <summary>
/// Текущий список запущенных задач. Содержит ключ метаданных и ссылку на запущенный Task.
/// </summary>
public IReadOnlyDictionary<Guid, IRunningBackgroundTaskData> ActiveTasks => activeTasks;
/// <summary>
/// Завершенные задачи.
/// </summary>
public IReadOnlyCollection<IRunningBackgroundTaskData> EndTasks => completedTasks;
/// <summary>
/// Экземпляры задач.
/// </summary>
public IReadOnlyCollection<IPRBackgroundTask> TaskInstance => registeredTaskInstances.ToList();
/// <summary>
/// Метаданные задач.
/// </summary>
public IReadOnlyCollection<IPRBackgroundTaskMetadata> Metadata => registeredTaskMetadata.ToList();
/// <summary>
/// Запустить фоновые задачи.
/// </summary>
public Task StartAsync()
/// <summary>
/// Запустить фоновую задачу.
/// ВАЖНО. Перед вызовом данного метода убедитесь, что метаданные либо уже загружены в раннер, либо сама задача хранит в себе метаданные.
/// Например через атрибут <see cref="PRBackgroundTaskAttribute"/> или реализовывает интерфейс <see cref="IPRBackgroundTaskMetadata"/>
/// </summary>
/// <param name="backgroundTask">Фоновая задача.</param>
public Task StartAsync(IPRBackgroundTask task)
/// <summary>
/// Запустить фоновую задачу.
/// </summary>
/// <param name="backgroundTask">Фоновая задача.</param>
/// <param name="metadata">Метаданные.</param>
public Task StartAsync(IPRBackgroundTask backgroundTask, IPRBackgroundTaskMetadata metadata)
/// <summary>
/// Останавливает выполнение всех запущенных фоновых задач.
/// </summary>
public async Task StopAsync()
/// <summary>
/// Останавливает выполнение указанной фоновой задачи.
/// </summary>
/// <param name="taskId">Идентификатор задачи.</param>
public async Task StopAsync(Guid taskId)
/// <summary>
/// Останавливает выполнение указанной фоновой задачи.
/// </summary>
/// <param name="metadata">Метаданные фоновой задачи.</param>
public async Task StopAsync(IPRBackgroundTaskMetadata metadata)
/// <summary>
/// Инициализация фоновых задач.
/// </summary>
/// <param name="metadata">Метаданные.</param>
/// <param name="tasks">Фоновые задачи.</param>
public void Initialize(IEnumerable<IPRBackgroundTaskMetadata> metadata, IEnumerable<IPRBackgroundTask> tasks)
#endregion
#region Методы
/// <summary>
/// Добавить метаданные в общую коллекцию.
/// </summary>
/// <param name="metadata"></param>
private bool AddMetadata(IPRBackgroundTaskMetadata metadata)
/// <summary>
/// Проверяем, что метаданные подходят только для другого бота.
/// </summary>
/// <param name="metadata">Метаданные фоновой задачи.</param>
/// <returns>True - если метаданные для другого бота.</returns>
private bool IsMetadataForAnotherBot(IPRBackgroundTaskMetadata metadata)
/// <summary>
/// Получает все зарегистрированные через DI экземпляры фоновых задач из указанного scope.
/// </summary>
/// <param name="scope">
/// Scope, из которого необходимо получить сервисы. Может быть null.
/// </param>
/// <returns>
/// Перечисление экземпляров <see cref="IPRBackgroundTask"/>.
/// Если <paramref name="scope"/> равен null или <see cref="IServiceProvider"/> внутри scope отсутствует, возвращается пустая коллекция.
/// </returns>
private IEnumerable<IPRBackgroundTask> ResolveBackgroundTasks(DisposableScope scope)
/// <summary>
/// Запустить фоновую задачу.
/// </summary>
/// <param name="metadata">Метаданные.</param>
/// <param name="data">Метаданные.</param>
/// <param name="token">Токен отмены.</param>
private async Task RunTaskAsync(IPRBackgroundTaskMetadata metadata, IRunningBackgroundTaskData data, CancellationToken token = default)
#region IPRTaskRunnerSubscriber
/// <summary>
/// Событие остановки фоновой задачи.
/// </summary>
/// <param name="botIds">Идентификаторы ботов.</param>
/// <param name="taskId">Идентификатор задачи.</param>
public void StopEvent(IEnumerable<long> botIds, Guid taskId)
/// <summary>
/// Событие остановки фоновой задачи.
/// </summary>
/// <param name="taskId">Идентификатор задачи.</param>
public void StopEvent(Guid taskId)
/// <summary>
/// Подписывает экземпляр на события EventBus.
/// </summary>
public void Subscribe()
/// <summary>
/// Отписывает экземпляр от событий EventBus.
/// </summary>
public void Unsubscribe()
/// <inheritdoc />
public void Dispose()
#endregion
#endregion
#region Конструкторы
/// <summary>
/// Конструктор.
/// </summary>
/// <param name="bot">Бот.</param>
public PRBackgroundTaskRunner(PRBotBase bot)
#endregion
}
}
Last updated