You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
6.8 KiB
C#

using System.Collections.Concurrent;
using Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask;
using Sln.Wcs.HikRoBotApi.Enum;
using Sln.Wcs.HikRoBotApi.Service;
using Sln.Wcs.HoistApi.Domain.Dto.HoistTaskExecutor;
using Sln.Wcs.HoistApi.Domain.Enum;
using Sln.Wcs.HoistApi.Service;
using Sln.Wcs.Model.Domain;
using Sln.Wcs.Repository.service;
namespace Sln.Wcs.Strategy;
public class TaskExecuteStrategy : ITaskExecuteStrategy
{
private readonly ILiveTaskQueueService _taskQueueService;
private readonly ILiveTaskDetailService _taskDetailService;
private readonly IHikRoBotService _hikRobotService;
private readonly IHoistApiService _hoistService;
// AGV 多车并发,默认最大 10 个并发
private readonly SemaphoreSlim _agvSemaphore = new(10, 10);
// 提升机按设备串行,每台提升机一次只能执行一个任务
private readonly ConcurrentDictionary<string, SemaphoreSlim> _hoistSemaphores = new();
public TaskExecuteStrategy(
ILiveTaskQueueService taskQueueService,
ILiveTaskDetailService taskDetailService,
IHikRoBotService hikRobotService,
IHoistApiService hoistService)
{
_taskQueueService = taskQueueService;
_taskDetailService = taskDetailService;
_hikRobotService = hikRobotService;
_hoistService = hoistService;
}
public Task ExecuteAsync(CancellationToken cancellationToken = default)
{
return Task.WhenAll(
ProcessCategory(1, cancellationToken), // 包材
ProcessCategory(2, cancellationToken), // 成品
ProcessCategory(3, cancellationToken) // 托盘
);
}
/// <summary>
/// 按任务类别轮询待执行任务,同一类别内多个任务并行处理
/// </summary>
private async Task ProcessCategory(int taskCategory, CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
var pendingTasks = _taskQueueService.Query(x =>
x.taskStatus == 1 && x.taskCategory == taskCategory);
if (pendingTasks.Count > 0)
{
await Parallel.ForEachAsync(pendingTasks, ct, async (task, innerCt) =>
{
await ProcessTask(task, innerCt);
});
}
}
catch (Exception ex)
{
Console.WriteLine($"任务类别 {taskCategory} 调度异常: {ex.Message}");
}
await Task.Delay(1000, ct);
}
}
/// <summary>
/// 处理单个任务:按顺序遍历明细步骤,依次下发到对应设备
/// </summary>
private async Task ProcessTask(LiveTaskQueue task, CancellationToken ct)
{
try
{
var details = _taskDetailService.Query(x =>
x.taskCode == task.taskCode && x.taskStatus == 1)
.OrderBy(x => x.objId)
.ToList();
foreach (var detail in details)
{
if (ct.IsCancellationRequested) return;
var success = await DispatchDetail(detail);
if (!success) break;
}
// 检查是否还有待执行的明细,若无则更新队列状态为执行中
var remainingPending = _taskDetailService.Query(x =>
x.taskCode == task.taskCode && x.taskStatus == 1);
if (remainingPending.Count == 0)
{
task.taskStatus = 2;
_taskQueueService.Update(task);
}
}
catch (Exception ex)
{
Console.WriteLine($"任务 {task.taskCode} 处理异常: {ex.Message}");
}
}
/// <summary>
/// 根据设备类型分发明细到对应设备 API
/// </summary>
private Task<bool> DispatchDetail(LiveTaskDetail detail)
{
return detail.deviceType switch
{
1 => DispatchToAgv(detail),
2 => DispatchToHoist(detail),
_ => Task.FromResult(false) // ConveyorLine 暂不处理
};
}
/// <summary>
/// 下发 AGV 任务,通过 HikRoBotApiAGV 多车可并发)
/// </summary>
private async Task<bool> DispatchToAgv(LiveTaskDetail detail)
{
await _agvSemaphore.WaitAsync();
try
{
var dto = new GenAgvSchedulingTaskDto
{
reqCode = detail.taskCode,
reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
clientCode = "WCS",
taskCode = detail.taskCode,
taskTyp = detail.taskType switch { 1 => "1", 2 => "2", _ => "0" },
taskMode = detail.taskType switch { 1 => "2", 2 => "1", _ => "0" },
wbCode = detail.startPoint,
ctnrCode = detail.palletBarcode,
materialLot = detail.materialBarcode,
positionCodePath = new List<Position>
{
new() { positionCode = detail.startPoint, type = "00" },
new() { positionCode = detail.endPoint, type = "00" }
}
};
var result = _hikRobotService.GetGenAgvSchedulingTask(dto);
if (result.code.Equals(HikRoBotStatusEnum.))
{
detail.taskStatus = 2;
_taskDetailService.Update(detail);
return true;
}
Console.WriteLine($"AGV 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}");
return false;
}
finally
{
_agvSemaphore.Release();
}
}
/// <summary>
/// 下发提升机任务,通过 HoistApi每台提升机串行
/// </summary>
private async Task<bool> DispatchToHoist(LiveTaskDetail detail)
{
var hoistCode = detail.startPoint ?? "default";
var semaphore = _hoistSemaphores.GetOrAdd(hoistCode, _ => new SemaphoreSlim(1, 1));
await semaphore.WaitAsync();
try
{
var dto = new HoistTaskExeDto
{
hoistCode = hoistCode,
taskCode = detail.taskCode,
startPoint = int.TryParse(detail.startPoint, out var s) ? s : 0,
endPoint = int.TryParse(detail.endPoint, out var e) ? e : 0
};
var result = _hoistService.HoistTaskExecutor(dto);
if (result.code.Equals(HoistStatusEnum.))
{
detail.taskStatus = 2;
_taskDetailService.Update(detail);
return true;
}
Console.WriteLine($"提升机 {hoistCode} 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}");
return false;
}
finally
{
semaphore.Release();
}
}
}