Вызов сервиса из контроллера

Рейтинг: 0Ответов: 0Опубликовано: 27.04.2023

Есть контроллер , Action метод которого должен создавать задачу(их может быть много разных), и возвращать, сообщение, что либо задачу успешно создана, либо эта задача уже в работе запустить можно только 1 экземпляр 1 вида задачи задачи.

[HttpPost]
public async Task<ActionResult> CreateTask([FromBody] CreateTaskDto createTaskDto)
{
    var command = new CreateTaskCommand()
    {
        Name = createTaskDto.Type.GetDisplayName(),
        Path = createTaskDto.Path,
        Type = createTaskDto.Type
    };

    var getExemplarTask = TaskCommander.Add(command.Type);
    if (getExemplarTask != null)
    {
        var vm = await Mediator.Send(command);

        getExemplarTask.Id = vm.Id;
        getExemplarTask?.Service.StartAsync(getExemplarTask.CancellationTokenSource.Token);
        
        return Ok(new AppResponse(message: $"Task {createTaskDto.Type.GetDisplayName()} succesfully created!", data: vm));
    }

    return Ok(new AppResponse(message: $"Task {createTaskDto.Type.GetDisplayName()} succesfully created!"));
}

в поле Type enum`ka с задачами

Так же есть второй Action метод, для прерывания задачи по Id задачи

[HttpGet("{Id}")]
public async Task<ActionResult> CancelTask(int Id)
{
    var command = new UpdateTaskCommand()
    {
        Id = Id,
        Status = Status.Canceled,
        FinishDate = DateTime.Now
    };

    TaskCommander.Cancel(Id);
    var vm = await Mediator.Send(command);

    return Ok(new AppResponse(message: $"Task {vm.Type.GetDisplayName()} succesfully canceled!", data: vm));
}

Пробовал создавать отдельный класс TaskController , в нем методы Add и Cancel и словарь типа IService | CancelationTokenSource (IService - интефейс реализуемый во всех сервисах).

При добавлении проверяем есть ли данная задача(по имени) в словаре, Если нет, то добавляем задачу, Через Task.Run(* , CancelationTokenSource.Token) запускаем и говорим медиатору ,чтобы сохранил в БД результат.

При удалении ищем в словаре так же по имени запущенный сервис, если он есть, то берем у него значение (CancelationTokenSource) и используем _cts.Cancel()

Однако эта конструкция работать оказалось. Столкнулся со следующими проблемами:

  1. Из-за Task.Run сохранение в БД происходит очень медленно
  2. Отмена задачи не происходит совсем

Вопрос: Как правильно реализовать создание и отмену задачи, а так же проверку на уникальность созданной задачи?

UPD:

Сам класс бизнес логики

public class CryptoFinderService : IService
{
    
    public CryptoFinderService()
    {
        
    }

    public async Task StartAsync(CancellationToken token)
    {
        /// Просто иммитация работы
        while (true) 
        {
            Debug.WriteLine("!!!!!");
            await Task.Delay(1);
        }
    }
}

класс для добавления и удаления задач

public static class TaskCommander
{
    private static List<ExemplarTask> _stackService = new();

    public static ExemplarTask? Add(TaskType type)
    {
        var service = SelectTask(type);

        var exemplar = new ExemplarTask()
        {
            Id = 0,
            Name = type.GetDisplayName(),
            Service = service,
            CancellationTokenSource = new CancellationTokenSource()
        };

        var taskIsContains = _stackService
            .Select(x => x.Name)
            .Any(x => x == exemplar.Name);

        if (taskIsContains)
        {
            return null;
        }

        _stackService.Add(exemplar);
        return exemplar;
    }

    public static void Cancel(int Id)
    {
        var exemplar = _stackService
            .FirstOrDefault(x => x.Id == Id);
        
        exemplar?.CancellationTokenSource.Cancel();
    }
    
    public static IService SelectTask(TaskType type)
    {
        switch (type)
        {
            case TaskType.CryptoFinder:
                return new CryptoFinderService();

            default:
                throw new TaskNotFound(nameof(TaskType));
        }
    }

    public class ExemplarTask
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IService Service { get; set; }
        public CancellationTokenSource CancellationTokenSource { get; set; }
    }
}

По моей логике класс TaskCommander должен руководить созданными задачами. Запускать и прерывать работу задач, но работать оно увы и ах не хочет

Ответы

Ответов пока нет.