RetryRobotTaskCommandHandler.cs 3.3 KB
using MassTransit;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.MessageBus.Commands;
using Rcs.Domain.Entities;
using Rcs.Domain.Repositories;

namespace Rcs.Infrastructure.MessageBus.Handlers.Commands;

/// <summary>
/// 重新执行任务命令处理器
/// 语义:取消当前任务后,创建一个同配置的新任务
/// </summary>
public class RetryRobotTaskCommandHandler : IConsumer<RetryRobotTaskCommand>
{
    private readonly ILogger<RetryRobotTaskCommandHandler> _logger;
    private readonly IRobotTaskRepository _robotTaskRepository;

    public RetryRobotTaskCommandHandler(
        ILogger<RetryRobotTaskCommandHandler> logger,
        IRobotTaskRepository robotTaskRepository)
    {
        _logger = logger;
        _robotTaskRepository = robotTaskRepository;
    }

    public async Task Consume(ConsumeContext<RetryRobotTaskCommand> context)
    {
        var command = context.Message;
        try
        {
            var task = await _robotTaskRepository.GetByIdAsync(command.TaskId, context.CancellationToken);
            if (task == null)
            {
                await context.RespondAsync(ApiResponse.Failed($"未找到任务ID为 {command.TaskId} 的任务"));
                return;
            }

            task.Cancel();
            await _robotTaskRepository.UpdateAsync(task, context.CancellationToken);

            var newTaskCode = await GenerateRetryTaskCodeAsync(task.TaskCode, context.CancellationToken);
            var newTask = new RobotTask();
            newTask.Create(
                taskCode: newTaskCode,
                taskName: task.TaskName ?? task.TaskCode,
                beginLocationId: task.BeginLocationId,
                endLocationId: task.EndLocationId,
                priority: task.Priority,
                taskTemplateId: task.TaskTemplateId,
                shelfCode: task.ShelfCode,
                containerId: task.ContainerID,
                source: task.Source
            );

            if (task.RobotId.HasValue)
            {
                newTask.Assign(task.RobotId.Value);
            }

            newTask.Relation = task.Relation;
            await _robotTaskRepository.AddAsync(newTask, context.CancellationToken);

            await context.RespondAsync(ApiResponse.Successful("重新执行成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "重新执行任务失败, TaskId: {TaskId}", command.TaskId);
            await context.RespondAsync(ApiResponse.Failed(ex.Message));
        }
    }

    private async Task<string> GenerateRetryTaskCodeAsync(string? oldTaskCode, CancellationToken cancellationToken)
    {
        var prefix = string.IsNullOrWhiteSpace(oldTaskCode) ? "T" : oldTaskCode;
        if (prefix.Length > 32)
        {
            prefix = prefix[..32];
        }

        const int maxRetryCount = 20;
        for (var i = 0; i < maxRetryCount; i++)
        {
            var candidate = $"{prefix}_r{DateTime.Now:MMddHHmmss}{Random.Shared.Next(10, 99)}";
            var existed = await _robotTaskRepository.AnyAsync(t => t.TaskCode == candidate, cancellationToken);
            if (!existed)
            {
                return candidate;
            }
        }

        return $"T{DateTime.Now:yyMMddHHmm}_{Guid.NewGuid().ToString("N")[..6].ToLower()}";
    }
}