public static bool CanJoinSimpleEvents(IEventCacheReadObject oldEvent, Event newEvent, TimeSpan joinInterval) { if (oldEvent == null) { return(false); } if (joinInterval == TimeSpan.Zero) { return(false); } // добавляем 1 секунду, т.к. при сохранении в БД мс теряются var maxJoinDate = oldEvent.EndDate.AddSeconds(1) + joinInterval; return(CanJoin(oldEvent, newEvent, maxJoinDate)); }
public static BulbSignal Create(DateTime processDate, IEventCacheReadObject eventObj, EventImportance noSignalImportance) { if (eventObj == null) { throw new ArgumentNullException("eventObj"); } return(new BulbSignal() { AccountId = eventObj.AccountId, EventId = eventObj.Id, IsSpace = eventObj.IsSpace, ActualDate = eventObj.ActualDate, Message = eventObj.Message, Status = MonitoringStatusHelper.Get(eventObj.Importance), NoSignalImportance = noSignalImportance, ProcessDate = processDate, StartDate = eventObj.StartDate }); }
/// <summary> /// Проверяет можно ли склеивать события. /// Все события склеиваются одинаково (простые и непрерывные). /// </summary> /// <param name="oldEvent"></param> /// <param name="newEvent"></param> /// <param name="maxJoinDate"></param> /// <returns></returns> private static bool CanJoin( IEventCacheReadObject oldEvent, Event newEvent, DateTime maxJoinDate) { // склеивать события разных версий нельзя if (newEvent.VersionLong != null && oldEvent.VersionLong != null && // если хотя бы у одного события версия неизвестна, то можно клеить newEvent.VersionLong != oldEvent.VersionLong) { return(false); } return(oldEvent.OwnerId == newEvent.OwnerId && oldEvent.Importance == newEvent.Importance && oldEvent.IsSpace == newEvent.IsSpace && // склеивать пробел с сигналом нельзя oldEvent.EventTypeId == newEvent.EventTypeId && oldEvent.JoinKeyHash == newEvent.JoinKeyHash && maxJoinDate >= newEvent.StartDate); }
public void ProcessEvent(Guid accountId, Guid componentId, IEventCacheReadObject eventObj) { var categories = new[] { Api.EventCategory.ApplicationError, Api.EventCategory.ComponentEvent }; if (categories.Contains(eventObj.Category) == false) { return; } var accountDbContext = Context.GetAccountDbContext(accountId); var component = accountDbContext.GetComponentRepository().GetById(componentId); // если выключен, то ничего не делаем if (component.CanProcess == false) { return; } // отфильтруем события, которые не могут влиять на статус // если событие НЕ длится if (eventObj.StartDate == eventObj.ActualDate) { // возможно такие события могут продлить EndDate до eventObj.StartDate // пока будем их игнорировать, чтобы сделать алгоритм проще return; } var statusId = component.EventsStatusId; var statusService = Context.BulbService; var noSignalImportance = Api.EventImportance.Unknown; // получаем или создаем статус (колбаску) var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = statusId }; using (var data = AllCaches.StatusDatas.Write(request)) { DateTime processDate = DateTime.Now; // событие из будущего (завершается через 5 минут) if (eventObj.EndDate > processDate + TimeSpan.FromMinutes(5)) { // пусть будет, эту проблему должен решать отправитель //return UpdateStatusResult.Canceled(); } // события из прошлого игнорируем, иначе будет ерунда при обновлении родительской колбасы // т.е. будет несоответствие наложения дочерних колбасок на родительскую if (eventObj.ActualDate <= processDate) { return; } // если событие протухло if (eventObj.ActualDate <= data.EndDate) { return; } var status = MonitoringStatusHelper.Get(eventObj.Importance); var signal = BulbSignal.Create(processDate, eventObj, noSignalImportance); // 0. если это первый сигнал после пробела if (data.HasSignal == false) { statusService.SetSignal(data.Id, signal); return; } // 1. событие менее важное, чем текущий статус if (status < data.Status) { // событие поменяло важность, нодо расчитать занова! if (data.LastEventId == eventObj.Id) { CalculateComponentEventsStatus(accountId, component.EventsStatusId); return; } // текущий статус актуальней if (data.ActualDate >= eventObj.ActualDate) { return; } // на актуальный статус менее важные события не влияют if (data.Actual(processDate)) { return; } // статус протух, а событие актуальное // нужно расчитать, т.к. могут быть более важные актуальные события CalculateComponentEventsStatus(accountId, component.EventsStatusId); return; } // 2. событие такой же важности как статус if (status == data.Status) { // продлеваем statusService.SetSignal(data.Id, signal); return; } // 3. событие более важное, чем текущий статус statusService.SetSignal(data.Id, signal); } }
protected IEventCacheReadObject CreateOrJoinSimpleEvent( Guid componentId, Event eventObj, Guid?oldEventId, TimeSpan joinInterval, Guid accountId, out bool isEventNew) { IEventCacheReadObject rLastEvent = null; if (oldEventId.HasValue) { rLastEvent = AllCaches.Events.Find(new AccountCacheRequest() { AccountId = accountId, ObjectId = oldEventId.Value }); } else { var accountDbContext = Context.DbContext.GetAccountDbContext(accountId); var repository = accountDbContext.GetEventRepository(); var lastEvent = repository.GetForJoin(eventObj); if (lastEvent != null) { rLastEvent = AllCaches.Events.GetForRead(lastEvent, accountId); } } if (rLastEvent != null) { var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = rLastEvent.Id }; if (AllCaches.Events.ExistsInStorage(request)) { using (var wLastEvent = AllCaches.Events.Write(request)) { bool canJoin = EventHelper.CanJoinSimpleEvents(wLastEvent, eventObj, joinInterval); if (canJoin) { // Можно склеивать UpdateJoinedEvent(accountId, componentId, wLastEvent, eventObj); isEventNew = false; wLastEvent.BeginSave(); return(wLastEvent); } } } } // Создадим новое { var accountDbContext = Context.DbContext.GetAccountDbContext(accountId); var eventRepository = accountDbContext.GetEventRepository(); isEventNew = true; eventRepository.Add(eventObj); accountDbContext.SaveChanges(); var wEvent = EventCacheWriteObject.CreateForUpdate(eventObj, accountId); AllCaches.Events.AddOrGet(wEvent); return(wEvent); } }
protected IBulbCacheReadObject SaveResultEvent( DateTime processDate, IUnitTestCacheReadObject unitTest, Event newEvent) { var request = new AccountCacheRequest() { AccountId = unitTest.AccountId, ObjectId = unitTest.StatusDataId }; using (var statusData = AllCaches.StatusDatas.Write(request)) { // сохраним результаты var eventService = Context.EventService; IEventCacheReadObject lastEvent = null; if (statusData.LastEventId.HasValue) { lastEvent = eventService.GetEventCacheOrNullById( unitTest.AccountId, statusData.LastEventId.Value); } // для системных проверок пробелы должны быть серыми, // чтобы из-за простоев агента зидиума не красить пользовательские проверки var noSignalImportance = unitTest.IsSystemType ? EventImportance.Unknown : EventImportance.Alarm; if (lastEvent == null) { // todo не понятно нужно ли в результаты проверок вставлять пробелы? // TryAddSpaceResultEvent(unitTest, newEvent, noSignalImportance); } else { // например, чтобы обрезать бесконечную актуальность у события "нет сигнала" if (lastEvent.ActualDate > newEvent.StartDate) { if (AllCaches.Events.ExistsInStorage(lastEvent)) { using (var wLastEvent = AllCaches.Events.Write(lastEvent)) { wLastEvent.ActualDate = newEvent.StartDate; wLastEvent.BeginSave(); } } } } // синхронная вставка // асинхронное создание объектов сильно усложняет код, поэтому будет создавать всё синхронно eventService.Add(unitTest.AccountId, newEvent); // асинхронная вставка //var newEventCache = EventCacheWriteObject.CreateForAdd(newEvent); //AllCaches.Events.AddNew(newEventCache); using (var wUnitTest = AllCaches.UnitTests.Write(unitTest)) { wUnitTest.LastExecutionDate = newEvent.EndDate; // расчитаем время следующего выполнения if (unitTest.PeriodSeconds > 0) { var nextTime = wUnitTest.NextDate ?? processDate; var period = TimeSpan.FromSeconds(wUnitTest.PeriodSeconds.Value); while (nextTime <= processDate) { nextTime = nextTime + period; } wUnitTest.NextDate = nextTime; } wUnitTest.BeginSave(); } // обновим статус var statusService = Context.BulbService; var signal = BulbSignal.Create(processDate, newEvent, noSignalImportance, unitTest.AccountId); var newStatus = statusService.SetSignal(unitTest.StatusDataId, signal); return(newStatus); } }