public WorkQueueProcessor(int numberThreads, ManualResetEvent terminateEvent, string name) { _terminateEvent = terminateEvent; _threadStop = new ManualResetEvent(false); using (IReadContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { IWorkQueueTypePropertiesEntityBroker broker = ctx.GetBroker <IWorkQueueTypePropertiesEntityBroker>(); WorkQueueTypePropertiesSelectCriteria criteria = new WorkQueueTypePropertiesSelectCriteria(); IList <WorkQueueTypeProperties> propertiesList = broker.Find(criteria); foreach (WorkQueueTypeProperties prop in propertiesList) { _propertiesDictionary.Add(prop.WorkQueueTypeEnum, prop); } } _threadPool = new WorkQueueThreadPool(numberThreads, WorkQueueSettings.Instance.PriorityWorkQueueThreadCount, WorkQueueSettings.Instance.MemoryLimitedWorkQueueThreadCount, _propertiesDictionary) { ThreadPoolName = name + " Pool" }; WorkQueueFactoryExtensionPoint ep = new WorkQueueFactoryExtensionPoint(); object[] factories = ep.CreateExtensions(); if (factories == null || factories.Length == 0) { // No extension for the workqueue processor. Platform.Log(LogLevel.Warn, "No WorkQueueFactory Extension found."); } else { foreach (object obj in factories) { IWorkQueueProcessorFactory factory = obj as IWorkQueueProcessorFactory; if (factory != null) { WorkQueueTypeEnum type = factory.GetWorkQueueType(); _extensions.Add(type, factory); } else { Platform.Log(LogLevel.Error, "Unexpected incorrect type loaded for extension: {0}", obj.GetType()); } } } }
/// <summary> /// The processing thread. /// </summary> /// <remarks> /// This method queries the database for WorkQueue entries to work on, and then uses /// a thread pool to process the entries. /// </remarks> public void Run() { // Force the alert to be displayed right away, if it happens DateTime lastLog = Platform.Time.AddMinutes(-61); if (!_threadPool.Active) { _threadPool.Start(); } Platform.Log(LogLevel.Info, "Work Queue Processor running..."); while (true) { if (_stop) { return; } bool threadsAvailable = _threadPool.CanQueueItem; bool memoryAvailable = WorkQueueSettings.Instance.WorkQueueMinimumFreeMemoryMB == 0 || SystemResources.GetAvailableMemory(SizeUnits.Megabytes) > WorkQueueSettings.Instance.WorkQueueMinimumFreeMemoryMB; if (threadsAvailable && memoryAvailable) { try { Model.WorkQueue queueListItem = GetWorkQueueItem(ServerPlatform.ProcessorId); if (queueListItem == null) { /* No result found, or reach max queue entries for each type */ _terminateEvent.WaitOne(WorkQueueSettings.Instance.WorkQueueQueryDelay, false); continue; } if (!_extensions.ContainsKey(queueListItem.WorkQueueTypeEnum)) { Platform.Log(LogLevel.Error, "No extensions loaded for WorkQueue item type: {0}. Failing item.", queueListItem.WorkQueueTypeEnum); //Just fail the WorkQueue item, not much else we can do FailQueueItem(queueListItem, "No plugin to handle WorkQueue type: " + queueListItem.WorkQueueTypeEnum); continue; } try { IWorkQueueProcessorFactory factory = _extensions[queueListItem.WorkQueueTypeEnum]; IWorkQueueItemProcessor processor = factory.GetItemProcessor(); // Enqueue the actual processing of the item to the thread pool. _threadPool.Enqueue(processor, queueListItem, ExecuteProcessor); } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected exception creating WorkQueue processor."); FailQueueItem(queueListItem, "Failure getting WorkQueue processor: " + e.Message); continue; } } catch (Exception e) { // Wait for only 1.5 seconds Platform.Log(LogLevel.Error, e, "Exception occured when processing WorkQueue item."); _terminateEvent.WaitOne(3000, false); } } else { if ((lastLog.AddMinutes(60) < Platform.Time) && !memoryAvailable) { lastLog = Platform.Time; Platform.Log(LogLevel.Error, "Unable to process WorkQueue entries, Minimum memory not available, minimum MB required: {0}, current MB available:{1}", WorkQueueSettings.Instance.WorkQueueMinimumFreeMemoryMB, SystemResources.GetAvailableMemory(SizeUnits.Megabytes)); ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Critical, "WorkQueue", AlertTypeCodes.NoResources, null, TimeSpan.Zero, "Unable to process WorkQueue entries, Minimum memory not available, minimum MB required: {0}, current MB available:{1}", WorkQueueSettings.Instance.WorkQueueMinimumFreeMemoryMB, SystemResources.GetAvailableMemory(SizeUnits.Megabytes)); } // wait for new opening in the pool or termination WaitHandle.WaitAny(new WaitHandle[] { _threadStop, _terminateEvent }, 3000, false); _threadStop.Reset(); } } }