private void TodayQueuePlan_OnOperatorPlanMetricsUpdated(object sender, QueuePlanEventArgs e) { if (OnOperatorPlanMetricsUpdated != null) { logger.Debug("Запуск обработчика для события [OperatorPlanMetricsUpdated] с кол-вом слушателей [{0}]", OnOperatorPlanMetricsUpdated.GetInvocationList().Length); OnOperatorPlanMetricsUpdated(this, new QueueInstanceEventArgs() { OperatorPlanMetrics = Mapper.Map<OperatorPlanMetrics, DTO.OperatorPlanMetrics>(e.OperatorPlanMetrics) }); } }
private void TodayQueuePlan_CurrentClientRequestPlanUpdated(object sender, QueuePlanEventArgs e) { if (OnCurrentClientRequestPlanUpdated != null) { var eventArgs = new QueueInstanceEventArgs() { Operator = Mapper.Map<Operator, DTO.Operator>(e.Operator) }; if (e.ClientRequestPlan != null) { logger.Debug("Текущий план запроса клиента у оператора [{0}] [{1}]", e.Operator, e.ClientRequestPlan); eventArgs.ClientRequestPlan = Mapper.Map<ClientRequestPlan, DTO.ClientRequestPlan>(e.ClientRequestPlan); } else { logger.Debug("У оператора [{0}] отсутствуют текущие запросы", e.Operator); } logger.Debug("Запуск обработчика для события [CurrentClientRequestPlanUpdated] с кол-вом слушателей [{0}]", OnCurrentClientRequestPlanUpdated.GetInvocationList().Length); OnCurrentClientRequestPlanUpdated(this, eventArgs); } }
private void TodayQueuePlan_OnBuilded(object sender, QueuePlanEventArgs e) { try { string directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "queue"); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } string file = Path.Combine(directory, string.Format("queue-plan-{0:00000}.txt", TodayQueuePlan.Version)); File.WriteAllLines(file, TodayQueuePlan.Report); } catch (Exception exception) { logger.Error(exception); } }
/// <summary> /// Построить план очереди /// </summary> /// <returns></returns> public void Build(TimeSpan planTime) { PlanTime = planTime; Report = new List<string>() { string.Format("Построение плана очереди на дату {0:dd.MM.yyyy} и время {1:hh\\:mm\\:ss}, номер недели {2}", PlanDate, PlanTime, WeekNumber) }; foreach (var o in OperatorsPlans) { clientRequests.AddRange(o.ClientRequestPlans.Select(p => p.ClientRequest)); o.ClientRequestPlans.Clear(); o.PlanTime = PlanTime; o.Interruptions = GetOperatorInterruptions(o.Operator); } clientRequests.AddRange(NotDistributedClientRequests.Select(n => n.ClientRequest)); NotDistributedClientRequests.Clear(); var conditions = new[] { new { Name = "Вызываемые", Predicate = new Predicate<ClientRequest>(r => r.State == ClientRequestState.Calling) }, new { Name = "Обслуживаемые", Predicate = new Predicate<ClientRequest>(r => r.State == ClientRequestState.Rendering) }, new { Name = "Переданные", Predicate = new Predicate<ClientRequest>(r => r.State == ClientRequestState.Redirected) }, new { Name = "Предварительная запись с определенными операторами", Predicate = new Predicate<ClientRequest>(r => r.Type == ClientRequestType.Early && r.Operator != null) }, new { Name = "Предварительная запись", Predicate = new Predicate<ClientRequest>(r => r.Type == ClientRequestType.Early) }, new { Name = "Живая очередь с приоритетом", Predicate = new Predicate<ClientRequest>(r => r.Type == ClientRequestType.Live && r.IsPriority) }, new { Name = "Живая очередь", Predicate = new Predicate<ClientRequest>(r => r.Type == ClientRequestType.Live) } }; clientRequests = clientRequests.Distinct().ToList(); foreach (var condition in conditions) { var conditionClientRequests = clientRequests .Where(new Func<ClientRequest, bool>(condition.Predicate)) .OrderByDescending(p => p.Service.Priority) .ThenBy(p => p.RequestTime) .ThenBy(p => p.CreateDate); Report.Add(string.Format("Планируется по условию [{0}] [{1}] запросов", condition.Name, conditionClientRequests.Count())); foreach (var conditionClientRequest in conditionClientRequests) { Report.Add(string.Format("Планируется запрос [{0}]", conditionClientRequest)); if (conditionClientRequest.RequestDate != PlanDate) { Report.Add("Дата запроса не соответствует дате плана очереди"); continue; } var schedule = GetServiceSchedule(conditionClientRequest.Service); Report.Add(string.Format("Определено расписание для услуги [{0}]", schedule)); try { OperatorPlan targetOperatorPlan; if (conditionClientRequest.Operator != null) { Report.Add(string.Format("Оператор {0} определен ранее для запроса", conditionClientRequest.Operator)); targetOperatorPlan = GetOperatorPlan(conditionClientRequest.Operator); } else { var serviceRenderingMode = conditionClientRequest.Type == ClientRequestType.Early ? ServiceRenderingMode.EarlyRequests : ServiceRenderingMode.LiveRequests; var renderings = GetServiceRenderings(schedule, conditionClientRequest.ServiceStep, serviceRenderingMode); Report.Add("Поиск потенциальных операторов"); var potentialOperatorsPlans = renderings .Where(r => r.Operator.IsActive) .Select(r => new { OperatorPlan = OperatorsPlans.FirstOrDefault(o => o.Operator.Equals(r.Operator)), Priority = r.Priority }).Where(r => r.OperatorPlan != null) .ToList(); foreach (var p in potentialOperatorsPlans) { Report.Add(string.Format("{0} {1}", p.OperatorPlan.Operator, p.OperatorPlan.Operator.Online ? "в сети" : "не в сети")); } if (PlanDate == DateTime.Today && schedule.OnlineOperatorsOnly) { Report.Add("Операторы не в сети игнорируются"); potentialOperatorsPlans.RemoveAll(p => !p.OperatorPlan.Operator.Online); } if (potentialOperatorsPlans.Count() == 0) { Report.Add("Операторы не найдены"); throw new Exception("В системе нет операторов способных обработать запрос"); } var requestTime = conditionClientRequest.RequestTime; if (requestTime < planTime) { requestTime = planTime; } var operatorPlanMetrics = potentialOperatorsPlans .Select(p => new { OperatorPlan = p.OperatorPlan, NearTimeInterval = p.OperatorPlan.GetNearTimeInterval(requestTime, schedule, conditionClientRequest.Type, conditionClientRequest.Subjects), IsOnline = p.OperatorPlan.Operator.Online, Availability = p.OperatorPlan.CurrentClientRequestPlan == null || !p.OperatorPlan.CurrentClientRequestPlan.ClientRequest.InWorking, DayWorkload = p.OperatorPlan.Metrics.DailyWorkload, PlaningWorkload = p.OperatorPlan.Metrics.PlaningWorkload }) .OrderBy(m => m.NearTimeInterval) .ThenByDescending(m => m.IsOnline) .ThenByDescending(m => m.Availability) .ThenBy(m => m.PlaningWorkload) .ToList(); Report.Add("Расчет метрик операторов"); foreach (var m in operatorPlanMetrics) { m.OperatorPlan.Metrics.Standing++; Report.Add(string.Format("{0} {1}, ближайший интервал времени: {2:hh\\:mm\\:ss}, доступность: {3}, дневная нагрузка: {4:hh\\:mm\\:ss}, планируемая нагрузка: {5:hh\\:mm\\:ss}", m.OperatorPlan, m.IsOnline ? "в сети" : "не в сети", m.NearTimeInterval, m.Availability ? "свободен" : "занят", m.DayWorkload, m.PlaningWorkload)); } targetOperatorPlan = operatorPlanMetrics.Select(m => m.OperatorPlan).First(); } if (targetOperatorPlan != null) { targetOperatorPlan.AddClientRequest(conditionClientRequest, schedule); Report.Add(string.Format("Оператор [{0}] назначен для [{1}]", targetOperatorPlan, conditionClientRequest)); } else { throw new Exception("Не удалось определить целевой план оператора"); } } catch (Exception exception) { NotDistributedClientRequests.Add(new NotDistributedClientRequest(conditionClientRequest, exception.Message)); } Report.Add(string.Empty); } clientRequests.RemoveAll(condition.Predicate); } foreach (var r in clientRequests) { NotDistributedClientRequests.Add(new NotDistributedClientRequest(r, "Ни один оператор не может обслужить запрос клиента")); } clientRequests.Clear(); Report.Add(string.Empty); foreach (var o in OperatorsPlans) { if (o.CurrentClientRequestPlan != null) { Report.Add(string.Format("{0} текущий запрос [{1}]", o.Operator, o.CurrentClientRequestPlan)); } foreach (var p in o.ClientRequestPlans) { Report.Add(string.Format("{0} запланирован в {1:hh\\:mm\\:ss} {2}", p.Position, p.StartTime, p)); } } if (OnCurrentClientRequestPlanUpdated != null) { logger.Info("Запуск обработчика для события [OnCurrentClientRequestPlanUpdated] с кол-вом слушателей [{0}]", OnCurrentClientRequestPlanUpdated.GetInvocationList().Length); foreach (var o in OperatorsPlans) { var e = new QueuePlanEventArgs() { Operator = o.Operator }; if (o.CurrentClientRequestPlan != null) { e.ClientRequestPlan = o.CurrentClientRequestPlan; } OnCurrentClientRequestPlanUpdated(this, e); } } if (OnOperatorPlanMetricsUpdated != null) { logger.Info("Запуск обработчика для события [OnOperatorPlanMetricsUpdated] с кол-вом слушателей [{0}]", OnOperatorPlanMetricsUpdated.GetInvocationList().Length); foreach (var o in OperatorsPlans) { OnOperatorPlanMetricsUpdated(this, new QueuePlanEventArgs() { OperatorPlanMetrics = o.Metrics }); } } Version++; logger.Info("Построение плана очереди завершено с версией [{0}]", Version); if (OnBuilded != null) { OnBuilded(this, new QueuePlanEventArgs()); } }