public bool EnqueueObject(QueueObjectAction obj) { #region Складываем задачу в память if (!obj.Action.IsHighLevelReliability) { ListQueueObjects.ListQueueActions.AddOrUpdate(obj, 0, Update); ChangeQueue(); return(true); } #endregion Складываем задачу в базу #region Складываем задачу в базу lock (_lockDb) { using (SQLiteConnection connection = new SQLiteConnection(_dbDsn)) { try { connection.Open(); string insSql = "INSERT INTO retro_queue (GUID, DT1970, OBJECT_XML, COUNT_ERROR) " + "VALUES (@GUID, @DT1970, @OBJECT_XML, @COUNT_ERROR)"; using (SQLiteCommand command = new SQLiteCommand(insSql, connection)) { SQLiteParameter guid = new SQLiteParameter("@GUID"); SQLiteParameter dt1970 = new SQLiteParameter("@DT1970"); SQLiteParameter objectXml = new SQLiteParameter("@OBJECT_XML"); SQLiteParameter countError = new SQLiteParameter("@COUNT_ERROR"); guid.Value = obj.Guid.ToString(); dt1970.Value = obj.Dt1970; objectXml.Value = obj.Action.ToXml(); countError.Value = obj.CountError; command.Parameters.Add(guid); command.Parameters.Add(dt1970); command.Parameters.Add(objectXml); command.Parameters.Add(countError); command.ExecuteNonQuery(); } ChangeQueue(); } catch (Exception e) { Log.Error(NameTh + "> ОШИБКА!!! Возникла ошибка при записи объекта в очередь!", e); return(false); } finally { connection.Close(); } } } return(true); #endregion }
/// <summary> /// Проверка валидности действия /// </summary> /// <param name="objectAction"></param> /// <returns></returns> public bool IsReceivedObject(QueueObjectAction objectAction) { TimeSpan timeLastError = DateTime.Now - objectAction.DateError; if (timeLastError.TotalMinutes < _minuteToReceiveError) { return(false); } if (objectAction.CountError > _configStorage.CountError) { _svcSignal.SendSignal(SysSignal.Define.ServiceFault); Log.Error("Превышено количество попыток выполнения задачи" + objectAction.Guid); _queueAction.DeleteRecord(objectAction); return(false); } return(true); }
public void DeleteRecord(QueueObjectAction record) { #region Удаляем задачу из памяти if (!record.Action.IsHighLevelReliability) { int i = 0; ListQueueObjects.ListQueueActions.TryRemove(record, out i); return; } #endregion #region Удаляем задачу из базы lock (_lockDb) { using (SQLiteConnection connection = new SQLiteConnection(_dbDsn)) { try { connection.Open(); string sql = "delete from retro_queue where GUID = @GUID"; using (SQLiteCommand command = new SQLiteCommand(sql, connection)) { SQLiteParameter guid = new SQLiteParameter("@GUID") { Value = record.Guid.ToString() }; command.Parameters.Add(guid); command.ExecuteNonQuery(); } } catch (Exception e) { Log.Error(NameTh + "> ОШИБКА!!! Возникла ошибка при удалении объекта из очереди! ID=" + record.Guid, e); } finally { connection.Close(); } } } #endregion }
public QueueObjectAction GetFirst() { List <QueueObjectAction> result = new List <QueueObjectAction>(); Random r = new Random(); if (ListQueueObjects.ListQueueActions != null && !ListQueueObjects.ListQueueActions.IsEmpty) { result.AddRange(ListQueueObjects.ListQueueActions.Keys); } lock (_lockDb) { using (SQLiteConnection connection = new SQLiteConnection(_dbDsn)) { try { connection.Open(); string sql = "select * from retro_queue"; using (SQLiteCommand command = new SQLiteCommand(sql, connection)) { using (SQLiteDataReader reader = command.ExecuteReader()) { while (reader.Read()) { QueueObjectAction g = FillQueueAction(reader); result.Add(g); } } } } catch (Exception e) { Log.Error(NameTh + "> ОШИБКА!!! Возникла ошибка при получении объекта из очереди!", e); } finally { connection.Close(); } } } if (result.Count == 0) { return(null); } List <QueueObjectAction> listQueue = new List <QueueObjectAction>(); List <QueueObjectAction> listErrorQueue = new List <QueueObjectAction>(); foreach (var action in result) { if (action.DateError == new DateTime()) { listQueue.Add(action); } else { listErrorQueue.Add(action); } } return(listQueue.Count > 0 ? listQueue[r.Next(0, listQueue.Count - 1)] : listErrorQueue[r.Next(0, listErrorQueue.Count - 1)]); }
private int Update(QueueObjectAction arg1, int arg2) { Random r = new Random(); return(r.Next(0, 100)); }
/// <summary> /// Удаляем выполненные действия /// </summary> /// <param name="objectAction"></param> private void RemoveActionRunning(QueueObjectAction objectAction) { int i; _listActionsRunning.TryRemove(objectAction.Guid, out i); }
/// <summary> /// В очереди появилась задача - выполняем. /// Метод всегда запускается в отдельном потоке (new Thread(ReceiveRetroProcess)) - не изменять это! /// </summary> private void ReceiveRetroProcess() { QueueObjectAction objectAction = null; try { if (_queueAction == null || _queueAction.IsEmptyQueue()) { return; } #if DEBUG Log.Info("По таймеру разбираем очередь "); #endif objectAction = _queueAction.GetFirst(); // Обрабатываем только новые действия if (objectAction == null || _listActionsRunning.ContainsKey(objectAction.Guid)) { return; } if (!IsReceivedObject(objectAction)) { Log.Info("Выполнение действия прервано " + objectAction.Action.GuidAction); return; } _listActionsRunning[objectAction.Guid] = 0; DateTime dtNow = DateTime.Now; // Отложим время выполнения действия если задана соответствующая настройка if (objectAction.Action.RunTimeOffset > 0) { Log.Info("Выполнение действия отложено " + objectAction.Action.GuidAction); Thread.Sleep(TimeSpan.FromSeconds(objectAction.Action.RunTimeOffset)); Log.Info("Выполнение действия возобновлено " + objectAction.Action.GuidAction); } var dataRegistry = Registry.GetNewRegistry(_rsduDbConf.DSN, _rsduDbConf.Login, _rsduDbConf.Password); dataRegistry.SetAppName(_rsduDbConf.AppName); lock (dataRegistry.Locker) { Log.Info("Количество задач в очереди до обработки " + _queueAction.Count()); _timerThread.Start(); var archives = new List <ParamData>(); // Получение кадра из бд RetroKadr kadr = GetKadr(objectAction.Action.KadrId, dataRegistry); if (kadr == null) { _timerThread.Stop(); RemoveActionRunning(objectAction); return; } var conditionsDates = new List <QueryConditionsDates>(); // Расчет периода и запрос архивов Dictionary <DateTime, DateTime> startFinish = new Dictionary <DateTime, DateTime>(); foreach (var queryCondition in objectAction.Action.QueryConditions) { DateTime start = GetDateStart(queryCondition, dtNow); DateTime finish = GetDateFinish(queryCondition.Interval, queryCondition.IntervalCount, start); conditionsDates.Add(new QueryConditionsDates(queryCondition, start, finish)); List <ParamData> archive = GetDataArc(start, finish, kadr, dataRegistry); if (archive != null) { archives.AddRange(archive); } startFinish.Add(start, finish); } IDataExporter dataExporter = new DataExporter(objectAction.Action, kadr, archives, conditionsDates); Log.Info("Выполняется задача " + objectAction.Guid); bool exported = dataExporter.Export(startFinish, dtNow); Log.Info("Выполнена задача " + objectAction.Guid + " - " + exported); if (exported) { _queueAction.DeleteRecord(objectAction); } else { _queueAction.DeleteRecord(objectAction); objectAction.CountError = objectAction.CountError + 1; _queueAction.EnqueueObject(objectAction); } _evGetRetro.Set(); _timerThread.Stop(); RemoveActionRunning(objectAction); #if DEBUG Log.Info("Количество задач в очереди после обработки " + _queueAction.Count()); #endif } dataRegistry = null; } catch (ThreadAbortException) { // При остановке сервиса все потоки грохаются с помощью Thread.Abort. // Предотвращаем появление исключения "Поток находился в процессе ожидания" из-за того, // что некоторые потоки находятся в приостановленном состоянии т.к. мы Thread.Sleep делаем Thread.ResetAbort(); } catch (Exception ex) { Log.Error("Не удалось выполнить задачу из очереди", ex); if (objectAction != null) { RemoveActionRunning(objectAction); } } }