private void ScheduleServiceInstance(ServiceInstance serviceInstance, TimeSpan avgExecutionTime) { AsLockable(serviceInstance).Unlock(_instanceLock); serviceInstance.SchedulingInfo.SchedulingStatus = SchedulingStatus.Scheduled; serviceInstance.StateChanged += Instance_StateChanged; AsLockable(serviceInstance).Lock(_instanceLock); // set service instance max execution time serviceInstance.Configuration.Limits.MaxExecutionTime = TimeSpan.FromMilliseconds(avgExecutionTime.TotalMilliseconds * Configuration.MaxExecutionTimeFactor); if (!_scheduledRequests.ContainsSignature(serviceInstance)) { WriteLog(String.Format("Move unscheduled request to scheduled list '{0}'", serviceInstance.DebugInfo())); _scheduledRequests.Add(serviceInstance); _unscheduledRequests.Remove(serviceInstance); } else { WriteLog(String.Format("Warning! Request '{0}' already exists in scheduled list", serviceInstance.DebugInfo()), LogMessageType.Warning); } }
//================================== #endregion #region Scheduling algorithms //================================== /// <summary> /// The main method of creating scheduler /// </summary> private void Schedule(bool reschedule = false) { lock (_unscheduledRequests) { lock (_scheduledRequests) { // Set need reschedule to false in order to avoid more schedule from other threads _needReschedule = false; #region Manage history and find services to schedule // ------------------------------------ // Move pending uninitialized services to the unscheduled list so they can be rescheduled foreach (ServiceInstance request in _scheduledRequests.RemoveNotActivated()) { if (request.SchedulingInfo.RequestedTime + request.SchedulingInfo.MaxDeviationAfter > DateTime.Now) { _unscheduledRequests.Add(request); } else { AsLockable(request).Unlock(_instanceLock); request.SchedulingInfo.SchedulingStatus = SchedulingStatus.CouldNotBeScheduled; AsLockable(request).Lock(_instanceLock); } } // Get Services for next time line foreach (ServiceInstance request in GetServicesForTimeLine(reschedule)) { _unscheduledRequests.Add(request); } // Copy unscheduled requests to an ordered list var servicesForNextTimeLine = new List <ServiceInstance>(_unscheduledRequests .OrderBy(schedulingdata => schedulingdata.SchedulingInfo.RequestedTime)); // ------------------------------------ #endregion #region Find Match services // ------------------------------------ //Same services or same services with same profile foreach (ServiceInstance serviceInstance in servicesForNextTimeLine) { //Get all services with same configurationID var requestsWithSameConfiguration = _scheduledRequests.GetWithSameConfiguration(serviceInstance); //Get all services with same profileID var requestsWithSameProfile = _scheduledRequests.GetWithSameProfile(serviceInstance); //Find the first available time this service with specific service and profile TimeSpan avgExecutionTime = GetAverageExecutionTime(serviceInstance.Configuration.ServiceName, Convert.ToInt32(serviceInstance.Configuration.Profile.Parameters["AccountID"]), _percentile); DateTime baseStartTime = (serviceInstance.SchedulingInfo.RequestedTime < DateTime.Now) ? DateTime.Now : serviceInstance.SchedulingInfo.RequestedTime; DateTime baseEndTime = baseStartTime.Add(avgExecutionTime); DateTime calculatedStartTime = baseStartTime; DateTime calculatedEndTime = baseEndTime; bool found = false; while (!found) { IOrderedEnumerable <ServiceInstance> whereToLookNext = null; int countedPerConfiguration = requestsWithSameConfiguration.Count(s => (calculatedStartTime >= s.SchedulingInfo.ExpectedStartTime && calculatedStartTime <= s.SchedulingInfo.ExpectedEndTime) || (calculatedEndTime >= s.SchedulingInfo.ExpectedStartTime && calculatedEndTime <= s.SchedulingInfo.ExpectedEndTime)); if (countedPerConfiguration < serviceInstance.Configuration.Limits.MaxConcurrentGlobal) { int countedPerProfile = requestsWithSameProfile.Count(s => (calculatedStartTime >= s.SchedulingInfo.ExpectedStartTime && calculatedStartTime <= s.SchedulingInfo.ExpectedEndTime) || (calculatedEndTime >= s.SchedulingInfo.ExpectedStartTime && calculatedEndTime <= s.SchedulingInfo.ExpectedEndTime)); if (countedPerProfile < serviceInstance.Configuration.Limits.MaxConcurrentPerProfile) { AsLockable(serviceInstance).Unlock(_instanceLock); serviceInstance.SchedulingInfo.ExpectedStartTime = calculatedStartTime; serviceInstance.SchedulingInfo.ExpectedEndTime = calculatedEndTime; serviceInstance.SchedulingInfo.SchedulingStatus = Services.SchedulingStatus.Scheduled; AsLockable(serviceInstance).Lock(_instanceLock); found = true; } else { whereToLookNext = requestsWithSameProfile; } } else { whereToLookNext = requestsWithSameConfiguration; } if (!found) { if (whereToLookNext == null) { throw new Exception("This should not have happened."); } calculatedStartTime = whereToLookNext.Where(s => s.SchedulingInfo.ExpectedEndTime >= calculatedStartTime).Min(s => s.SchedulingInfo.ExpectedEndTime); if (calculatedStartTime < DateTime.Now) { calculatedStartTime = DateTime.Now; } //Get end time calculatedEndTime = calculatedStartTime.Add(avgExecutionTime); ////remove unfree time from servicePerConfiguration and servicePerProfile if (calculatedStartTime <= _timeLineTo) { requestsWithSameConfiguration = from s in requestsWithSameConfiguration where s.SchedulingInfo.ExpectedEndTime > calculatedStartTime orderby s.SchedulingInfo.ExpectedStartTime select s; requestsWithSameProfile = from s in requestsWithSameProfile where s.SchedulingInfo.ExpectedEndTime > calculatedStartTime orderby s.SchedulingInfo.ExpectedStartTime select s; } } } if (serviceInstance.SchedulingInfo.ExpectedDeviation <= serviceInstance.SchedulingInfo.MaxDeviationAfter || serviceInstance.SchedulingInfo.MaxDeviationAfter == TimeSpan.Zero) { AsLockable(serviceInstance).Unlock(_instanceLock); serviceInstance.SchedulingInfo.SchedulingStatus = SchedulingStatus.Scheduled; serviceInstance.StateChanged += new EventHandler(Instance_StateChanged); AsLockable(serviceInstance).Lock(_instanceLock); // Legacy stuff //TODO: MAXEXECUTIONTIME TimeSpan maxExecutionTime = TimeSpan.FromMilliseconds(avgExecutionTime.TotalMilliseconds * double.Parse(AppSettings.Get(this, "MaxExecutionTimeProduct"))); serviceInstance.Configuration.Limits.MaxExecutionTime = maxExecutionTime; _scheduledRequests.Add(serviceInstance); _unscheduledRequests.Remove(serviceInstance); } } #endregion } SchedulingInformationEventArgs args = new SchedulingInformationEventArgs(); args.ScheduleInformation = new List <ServiceInstance>(); foreach (var scheduleService in _scheduledRequests) { args.ScheduleInformation.Add(scheduleService); } OnNewScheduleCreated(args); NotifyServicesToRun(); } }