PIbd-21_MasenkinMS_Aircraft.../AircraftPlant/AircraftPlantBusinessLogic/BusinessLogics/WorkModeling.cs
2024-04-22 19:08:56 +04:00

233 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AircraftPlantContracts.BindingModels;
using AircraftPlantContracts.BusinessLogicsContracts;
using AircraftPlantContracts.SearchModels;
using AircraftPlantContracts.ViewModels;
using AircraftPlantDataModels.Enums;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AircraftPlantBusinessLogic.BusinessLogics
{
/// <summary>
/// Реализация интерфейса бизнес-логики для имитации деятельности исполнителей
/// </summary>
public class WorkModeling : IWorkProcess
{
/// <summary>
/// Логгер
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Рандом
/// </summary>
private readonly Random _rnd;
private readonly object orderLock = new object();
private readonly object waitingOrderLock = new object();
/// <summary>
/// Бизнес-логика для заказов
/// </summary>
private IOrderLogic? _orderLogic;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="logger"></param>
public WorkModeling(ILogger<WorkModeling> logger)
{
_logger = logger;
_rnd = new Random(1000);
}
/// <summary>
/// Имитация рабочего процесса
/// </summary>
/// <param name="implementerLogic"></param>
/// <param name="orderLogic"></param>
public void DoWork(IImplementerLogic implementerLogic, IOrderLogic orderLogic)
{
_orderLogic = orderLogic;
var implementers = implementerLogic.ReadList(null);
if (implementers == null)
{
_logger.LogWarning("DoWork. Implementers is null");
return;
}
var orders = _orderLogic.ReadList(new OrderSearchModel { Status = OrderStatus.Принят });
_logger.LogDebug("DoWork for {Count} orders", orders?.Count);
foreach (var implementer in implementers)
{
Task.Run(() => WorkerWorkAsync(implementer, orders));
}
}
/// <summary>
/// Имитация работы исполнителя
/// </summary>
/// <param name="implementer"></param>
/// <param name="orders"></param>
private async Task WorkerWorkAsync(ImplementerViewModel implementer, List<OrderViewModel> orders)
{
if (_orderLogic == null || implementer == null)
{
return;
}
// Выполняем заказы в статусе "Ожидание"
await RunOrderInWaiting(implementer);
// Выполняем заказы в статусе "Выполняется"
await RunOrderInWork(implementer);
await Task.Run(() =>
{
foreach (var order in orders)
{
try
{
_logger.LogDebug("DoWork. Worker {Id} try get order {Order}", implementer.Id, order.Id);
// пытаемся назначить заказ на исполнителя
lock (orderLock)
{
_orderLogic.TakeOrderInWork(new OrderBindingModel
{
Id = order.Id,
ImplementerId = implementer.Id
});
}
// делаем работу
Thread.Sleep(implementer.WorkExperience * _rnd.Next(100, 1000) * order.Count);
_logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, order.Id);
_orderLogic.DeliveryOrder(new OrderBindingModel
{
Id = order.Id
});
}
// кто-то мог уже перехватить заказ, игнорируем ошибку
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Error try get work");
}
// заканчиваем выполнение имитации в случае иной ошибки
catch (Exception ex)
{
_logger.LogError(ex, "Error while do work");
throw;
}
// отдыхаем
Thread.Sleep(implementer.Qualification * _rnd.Next(10, 100));
}
});
}
/// <summary>
/// Ищем заказ, которые уже в работе (вдруг исполнителя прервали)
/// </summary>
/// <param name="implementer"></param>
/// <returns></returns>
private async Task RunOrderInWork(ImplementerViewModel implementer)
{
if (_orderLogic == null || implementer == null)
{
return;
}
try
{
var runOrder = await Task.Run(() => _orderLogic.ReadElement(new OrderSearchModel
{
ImplementerId = implementer.Id,
Status = OrderStatus.Выполняется
}));
if (runOrder == null)
{
return;
}
_logger.LogDebug("DoWork. Worker {Id} back to order {Order}", implementer.Id, runOrder.Id);
// доделываем работу
Thread.Sleep(implementer.WorkExperience * _rnd.Next(100, 300) * runOrder.Count);
_logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, runOrder.Id);
_orderLogic.DeliveryOrder(new OrderBindingModel
{
Id = runOrder.Id
});
// отдыхаем
Thread.Sleep(implementer.Qualification * _rnd.Next(10, 100));
}
// заказа может не быть, просто игнорируем ошибку
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Error try get work");
}
// а может возникнуть иная ошибка, тогда просто заканчиваем выполнение имитации
catch (Exception ex)
{
_logger.LogError(ex, "Error while do work");
throw;
}
}
/// <summary>
/// Ищем заказ, которые в ожидании
/// </summary>
/// <param name="implementer"></param>
/// <returns></returns>
private async Task RunOrderInWaiting(ImplementerViewModel implementer)
{
if (_orderLogic == null || implementer == null)
{
return;
}
try
{
var orders = await Task.Run(() => _orderLogic.ReadList(new OrderSearchModel
{
ImplementerId = implementer.Id,
Status = OrderStatus.Ожидание
}));
if (orders == null)
{
return;
}
// доделываем работу
foreach (var order in orders)
{
_logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, order.Id);
lock (waitingOrderLock)
{
_orderLogic.DeliveryOrder(new OrderBindingModel
{
Id = order.Id
});
}
// отдыхаем
Thread.Sleep(implementer.Qualification * _rnd.Next(10, 100));
}
}
// заказа может не быть, просто игнорируем ошибку
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Error try get work");
}
// а может возникнуть иная ошибка, тогда просто заканчиваем выполнение имитации
catch (Exception ex)
{
_logger.LogError(ex, "Error while do work");
throw;
}
}
}
}