public IEventCacheReadObject JoinEvent(Guid accountId, Guid componentId, JoinEventData joinEventData) { // Проверим, что компонент вообще есть var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; var component = AllCaches.Components.Find(componentRequest); if (component == null) { throw new UnknownComponentIdException(componentId, accountId); } if (component.CanProcess == false) { throw new ResponseCodeException(Zidium.Api.ResponseCode.ObjectDisabled, "Компонент выключен"); } // проверка лимитов var accountDbContext = Context.GetAccountDbContext(accountId); var limitChecker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); limitChecker.CheckEventsRequestsPerDay(accountDbContext); // Проверим лимит размера хранилища var size = joinEventData.Message != null ? joinEventData.Message.Length * 2 : 0; limitChecker.CheckStorageSize(accountDbContext, size); var eventType = Context.EventTypeService.GetOneById(joinEventData.TypeId ?? Guid.Empty, accountId); // расчитаем важность joinEventData.Importance = GetEventImportance(joinEventData.Importance, eventType.Category); var localEvent = CreateEvent( accountId, joinEventData.StartDate, joinEventData.StartDate, joinEventData.Count, joinEventData.Version, joinEventData.Importance, TimeSpan.FromSeconds(joinEventData.JoinInterval ?? 0), joinEventData.Message, null, eventType, componentId, joinEventData.JoinKey ?? 0); var joinInterval = (joinEventData.JoinInterval.HasValue) ? TimeSpan.FromSeconds(joinEventData.JoinInterval.Value) : (eventType.JoinInterval ?? TimeSpan.Zero); var dbEvent = ProcessSimpleEvent(componentId, localEvent, joinEventData.EventId, joinInterval, accountId); limitChecker.AddEventsSizePerDay(accountDbContext, size); return(dbEvent); }
public IBulbCacheReadObject GetComponentInternalState(Guid accountId, Guid componentId, bool recalc = false) { // перед отправкой актуализируем все статусы if (recalc) { CalculateAllStatuses(accountId, componentId); } var component = GetComponentById(accountId, componentId); var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = component.InternalStatusId }; return(AllCaches.StatusDatas.Find(request)); }
public IUnitTestTypeCacheReadObject UpdateUnitTestType(Guid accountId, UpdateUnitTestTypeRequestData data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.UnitTestTypeId == null) { throw new ParameterRequiredException("UnitTestTypeId"); } var lockObject = LockObject.ForUnitTestType(data.UnitTestTypeId.Value); lock (lockObject) { var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = data.UnitTestTypeId.Value }; var unitTestType = AllCaches.UnitTestTypes.Read(request); // Если поменялось системное имя, то проверим, что нет другого типа проверки с таким системным именем if (!string.Equals(unitTestType.SystemName, data.SystemName, StringComparison.OrdinalIgnoreCase)) { var anotherUnitTestType = AllCaches.UnitTestTypes.FindByName(accountId, data.SystemName); if (anotherUnitTestType != null && anotherUnitTestType.Id != unitTestType.Id) { throw new ArgumentException("Тип проверки с таким системным именем уже существует"); } } using (var unitTestTypeWrite = AllCaches.UnitTestTypes.Write(request)) { unitTestTypeWrite.SystemName = data.SystemName; unitTestTypeWrite.DisplayName = data.DisplayName; unitTestTypeWrite.ActualTimeSecs = data.ActualTimeSecs; unitTestTypeWrite.NoSignalColor = data.NoSignalColor; unitTestTypeWrite.BeginSave(); unitTestTypeWrite.WaitSaveChanges(); } return(AllCaches.UnitTestTypes.Read(request)); } }
public IMetricTypeCacheReadObject GetOrCreateType(Guid accountId, string name) { if (name == null) { throw new ArgumentNullException("name"); } if (accountId == Guid.Empty) { throw new ArgumentException("accountId == Guid.Empty"); } var metricTypeId = AllCaches.MetricTypes.GetOrCreateTypeId(accountId, name); var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = metricTypeId }; return(AllCaches.MetricTypes.Find(request)); }
public void DeleteUnitTestType(Guid accountId, Guid unitTestTypeId) { var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = unitTestTypeId }; using (var unitTest = AllCaches.UnitTestTypes.Write(request)) { unitTest.IsDeleted = true; unitTest.BeginSave(); unitTest.WaitSaveChanges(); } var checker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); checker.RefreshUnitTestTypesCount(); }
protected IMetricCacheReadObject FindMetric(Guid accountId, Guid componentId, Guid metricTypeId) { // получим компонент var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; var component = AllCaches.Components.Find(componentRequest); if (component == null) { throw new UnknownComponentIdException(componentId, accountId); } // получим ссылку на метрику var metricReference = component.Metrics.FindByMetricTypeId(metricTypeId); if (metricReference == null) { return(null); } // получим метрику по ссылке var metricRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = metricReference.Id }; var metric = AllCaches.Metrics.Find(metricRequest); if (metric == null) { // такого быть НЕ должно, т.к. у компонента есть ссылка на метрику throw new Exception("metric == null"); } return(metric); }
protected Component Add(Component component, Guid accountId) { if (component == null) { throw new ArgumentNullException("component"); } component.CreatedDate = DateTime.Now; if (component.Parent != null) { if (component.ComponentTypeId == SystemComponentTypes.Root.Id) { throw new ResponseCodeException( ResponseCode.UnknownComponentTypeId, "Нельзя создавать экземпляры компонентов с типом Root"); } component.ParentId = component.Parent.Id; component.ParentEnable = component.Parent.CanProcess; var parentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = component.Parent.Id }; var parent = AllCaches.Components.Find(parentRequest); if (parent == null) { throw new Exception("parent == null"); } var child = parent.Childs.FindByName(component.SystemName); if (child != null) { throw new Exception("У родителя уже есть компонент с таким SystemName"); } } component.ExternalStatus = CreateStatusData(component, Api.EventCategory.ComponentExternalStatus, accountId); component.InternalStatus = CreateStatusData(component, Api.EventCategory.ComponentInternalStatus, accountId); component.EventsStatus = CreateStatusData(component, Api.EventCategory.ComponentEventsStatus, accountId); component.UnitTestsStatus = CreateStatusData(component, Api.EventCategory.ComponentUnitTestsStatus, accountId); component.MetricsStatus = CreateStatusData(component, Api.EventCategory.ComponentMetricsStatus, accountId); component.ChildComponentsStatus = CreateStatusData(component, Api.EventCategory.ComponentChildsStatus, accountId); // обновим ссылку на компонент var statuses = component.GetAllStatuses(); foreach (var statusData in statuses) { statusData.ComponentId = component.Id; statusData.Component = component; } component.LogConfig = new LogConfig() { ComponentId = component.Id, Component = component, Enabled = true, IsFatalEnabled = true, IsErrorEnabled = true, IsWarningEnabled = true, IsInfoEnabled = true, IsDebugEnabled = true, IsTraceEnabled = true, LastUpdateDate = component.CreatedDate }; var accountDbContext = Context.GetAccountDbContext(accountId); accountDbContext.Components.Add(component); accountDbContext.SaveChanges(); // обновим в кэше ссылки на дочерние компоненты у родителя if (component.Parent != null) { var parentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = component.Parent.Id }; using (var parent = AllCaches.Components.Write(parentRequest)) { var componentRef = new CacheObjectReference(component.Id, component.SystemName); parent.WriteChilds.Add(componentRef); parent.BeginSave(); } } return(component); }
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); } }
public Guid CreateMetric(Guid accountId, Guid componentId, Guid metricTypeId) { // получаем компонент var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; using (var component = AllCaches.Components.Write(componentRequest)) { var child = component.Metrics.FindByMetricTypeId(metricTypeId); if (child != null) { throw new UserFriendlyException("У компонента уже есть метрика данного типа"); } // сохраняем метрику в БД using (var accountDbContext = AccountDbContext.CreateFromAccountIdLocalCache(accountId)) { // Проверим лимиты var limitChecker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); limitChecker.CheckMaxMetrics(accountDbContext); var processDate = DateTime.Now; var metricId = Guid.NewGuid(); var statusData = Context.BulbService.CreateBulb( accountId, processDate, EventCategory.MetricStatus, metricId); // загрузим в новый контекст statusData = accountDbContext.Bulbs.Find(statusData.Id); var metric = new Metric() { Id = metricId, BeginDate = processDate, ActualDate = processDate.AddDays(1), ComponentId = component.Id, Enable = true, IsDeleted = false, MetricTypeId = metricTypeId, ParentEnable = component.CanProcess, StatusDataId = statusData.Id, //StatusData = statusData, CreateDate = DateTime.Now, Value = null }; statusData.MetricId = metric.Id; statusData.Metric = metric; var repository = accountDbContext.GetMetricRepository(); repository.Add(metric); accountDbContext.SaveChanges(); // обновим статистику лимитов limitChecker.RefreshMetricsCount(); // обновляем ссылки у компонента var metricReference = new CacheObjectReference(metric.Id, metricTypeId.ToString()); component.WriteMetrics.Add(metricReference); component.BeginSave(); return(metric.Id); } } }
public void DeleteMetric(Guid accountId, DeleteMetricRequestData data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.MetricId == null) { throw new ParameterRequiredException("MetricId"); } // удаляем метрику Guid componentId; Guid statusDataId; Guid componentMetricsStatusDataId; var metricRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = data.MetricId.Value }; using (var metric = AllCaches.Metrics.Write(metricRequest)) { componentId = metric.ComponentId; statusDataId = metric.StatusDataId; metric.IsDeleted = true; metric.BeginSave(); metric.WaitSaveChanges(); } // Проверим лимиты var limitChecker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); limitChecker.RefreshMetricsCount(); // удаляем колбасу метрики var statusDataRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = statusDataId }; using (var statusData = AllCaches.StatusDatas.Write(statusDataRequest)) { statusData.IsDeleted = true; statusData.BeginSave(); } // удаляем ссылку на метрику в компоненте var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; using (var component = AllCaches.Components.Write(componentRequest)) { componentMetricsStatusDataId = component.MetricsStatusId; component.WriteChilds.Delete(data.MetricId.Value); component.BeginSave(); } // обновим колбасу метрик компонента var componentMetricsStatusDataIds = new List <Guid>(); var component1 = AllCaches.Components.Find(componentRequest); foreach (var metricRef in component1.Metrics.GetAll()) { var metric = AllCaches.Metrics.Find(new AccountCacheRequest() { AccountId = accountId, ObjectId = metricRef.Id }); if (metric == null) { throw new Exception("metric == null"); } if (metric.IsDeleted) { continue; } componentMetricsStatusDataIds.Add(metric.StatusDataId); } Context.BulbService.CalculateByChilds( accountId, componentMetricsStatusDataId, componentMetricsStatusDataIds); }
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); } }
public IEventCacheReadObject SendEvent(Guid accountId, Guid componentId, SendEventData message) { // Проверим, что компонент вообще есть var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; var component = AllCaches.Components.Find(componentRequest); if (component == null) { throw new UnknownComponentIdException(componentId, accountId); } if (component.CanProcess == false) { throw new ResponseCodeException(Zidium.Api.ResponseCode.ObjectDisabled, "Компонент выключен"); } // проверка лимитов var accountDbContext = Context.GetAccountDbContext(accountId); var limitChecker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); limitChecker.CheckEventsRequestsPerDay(accountDbContext); // Проверим лимит размера хранилища var size = message.GetSize(); limitChecker.CheckStorageSize(accountDbContext, size); // todo нет проверки обязательных параметров FixEventMessageNames(message); FixEventMessageTypeCode(message); FixEventMessageJoinKey(message); // todo не уверен, что нужно менять ключ склейки при разных версиях (но склеивать с разными версиями нельзя!) FixEventMessageJoinInterval(message); // категория if (message.Category == null) { message.Category = EventCategory.ComponentEvent; } // важность message.Importance = GetEventImportance(message.Importance, message.Category.Value); if (message.StartDate == null) { message.StartDate = DateTime.Now; } var eventType = GetOrCreateEventType( accountId, message.Category.Value, message.TypeSystemName, message.TypeDisplayName, component.ComponentTypeId, message.TypeCode); var joinTime = DataConverter.GetTimeSpanFromSeconds(message.JoinInterval); var localEvent = CreateEvent( accountId, message.StartDate, message.StartDate, message.Count, message.Version, message.Importance, TimeSpan.FromMinutes(1), message.Message, message.Properties, eventType, componentId, message.JoinKey ?? 0); // eventType.JoinInterval стоит на первом месте, чтобы можно было изменить поведение БЕЗ перекомпиляции кода var joinInterval = eventType.JoinInterval ?? joinTime ?? TimeSpan.Zero; if (!EventCategoryHelper.IsCustomerEventCategory(eventType.Category)) { throw new Exception("Недопустимая категория события: " + eventType.Category); } var result = ProcessSimpleEvent(componentId, localEvent, null, joinInterval, accountId); limitChecker.AddEventsRequestsPerDay(accountDbContext); limitChecker.AddEventsSizePerDay(accountDbContext, size); // если есть закрытый или тестируемый дефект и событие - новая ошибка, то переоткроем дефект if (eventType.Defect != null) { var defectStatus = eventType.Defect.GetStatus(); if ((defectStatus == DefectStatus.Closed || defectStatus == DefectStatus.Testing) && !EventIsOld(eventType.OldVersion, result.Version)) { var defectService = accountDbContext.GetDefectService(); defectService.AutoReopen(accountId, eventType.Defect); accountDbContext.SaveChanges(); } } // проверим "событие из будущего" CheckEventStartDate(message, accountId, eventType.Id, result.Id); return(result); }
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); } }
public void Delete(Guid accountId, Guid unitTestId) { // удаляем юнит-тест var unitTestRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = unitTestId }; Guid componentId; Guid componentUnitTestsStatudDataId; Guid unitTestStatusDataId; using (var unitTest = AllCaches.UnitTests.Write(unitTestRequest)) { componentId = unitTest.ComponentId; unitTestStatusDataId = unitTest.StatusDataId; unitTest.IsDeleted = true; unitTest.BeginSave(); } // удаляем колбасу юнит-теста var statusDataRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = unitTestStatusDataId }; using (var statusData = AllCaches.StatusDatas.Write(statusDataRequest)) { statusData.IsDeleted = true; statusData.BeginSave(); } // удаляем ссылку на юнит-тест в компоненте var componentRequest = new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }; using (var component = AllCaches.Components.Write(componentRequest)) { componentUnitTestsStatudDataId = component.UnitTestsStatusId; component.WriteUnitTests.Delete(unitTestId); component.BeginSave(); } // обновляем статус колбаски тестов var allUnitTestsStatusDataIds = new List <Guid>(); var component1 = AllCaches.Components.Find(new AccountCacheRequest() { AccountId = accountId, ObjectId = componentId }); foreach (var unitTestRef in component1.UnitTests.GetAll()) { var unitTest = AllCaches.UnitTests.Find(new AccountCacheRequest() { AccountId = accountId, ObjectId = unitTestRef.Id }); if (unitTest != null && unitTest.IsDeleted == false) { allUnitTestsStatusDataIds.Add(unitTest.StatusDataId); } } var statuservice = Context.BulbService; statuservice.CalculateByChilds(accountId, componentUnitTestsStatudDataId, allUnitTestsStatusDataIds); var checker = AccountLimitsCheckerManager.GetCheckerForAccount(accountId); checker.RefreshApiChecksCount(); }
public void UpdateUnitTest(Guid accountId, UpdateUnitTestRequestData data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.UnitTestId == null) { throw new ParameterRequiredException("UnitTestId"); } if (data.ComponentId == null) { throw new ParameterRequiredException("ComponentId"); } if (data.UnitTestId == Guid.Empty) { throw new ParameterErrorException("UnitTestId не может быть Guid.Empty"); } if (data.DisplayName == null) { throw new ParameterRequiredException("DisplayName"); } if (string.IsNullOrWhiteSpace(data.DisplayName)) { throw new ParameterErrorException("DisplayName не может быть пустым"); } //if (data.ErrorColor == null) //{ // throw new ParameterRequiredException("ErrorColor"); //} // SystemName сейчас не настраивается через GUI //if (data.SystemName == null) //{ // throw new ParameterRequiredException("SystemName"); //} //получим компонент, чтобы убедится, что он принадлежит аккаунту var req = new AccountCacheRequest() { AccountId = accountId, ObjectId = data.ComponentId.Value }; var component = AllCaches.Components.Find(req); if (component == null) { throw new UnknownComponentIdException(data.ComponentId.Value, accountId); } var request = new AccountCacheRequest() { AccountId = accountId, ObjectId = data.UnitTestId.Value }; // сохраним изменения IUnitTestCacheReadObject unitTestCache = null; using (var unitTest = AllCaches.UnitTests.Write(request)) { unitTestCache = unitTest; // период выполнения проверки if (unitTest.IsSystemType) { // не для всех системных проверок можно указывать период (для проверки домена нельзя) if (SystemUnitTestTypes.CanEditPeriod(unitTest.TypeId)) { if (data.PeriodSeconds == null) { throw new ParameterRequiredException("Period"); } if (data.PeriodSeconds.Value < 60) { throw new ParameterErrorException("Период проверки НЕ может быть меньше 1 минуты"); } unitTest.PeriodSeconds = (int)data.PeriodSeconds.Value; } // чтобы выполнить проверку прямо сейчас с новыми параметрами и увидеть результат unitTest.NextDate = DateTime.Now; } unitTest.DisplayName = data.DisplayName; unitTest.ComponentId = data.ComponentId.Value; unitTest.ErrorColor = data.ErrorColor; unitTest.NoSignalColor = data.NoSignalColor; unitTest.ActualTime = TimeSpanHelper.FromSeconds(data.ActualTime); if (data.SimpleMode.HasValue) { unitTest.SimpleMode = data.SimpleMode.Value; } unitTest.BeginSave(); } // ждем сохранения в кэше unitTestCache.WaitSaveChanges(); }