/// <summary> /// Get task that has been marked for cancellation. /// </summary> /// <param name="specification">The <see cref="TaskRequestSpecification"/> instance.</param> /// <param name="taskIds">List of tasks' identifiers that have been canceled.</param> /// <returns>True if there is at minimum one task that has been marked for cancel.</returns> public bool TryGetCancelTasks(TaskRequestSpecification specification, out List <Int64> taskIds) { const string selectStatement = "select [Id] from {0}.{1} where [QueueId] = {2} and [ServerId] = {3} and [State] = {4}"; string sqlCommand = string.Format(selectStatement, sqlSettings.WiseQueueDefaultSchema, taskTableName, specification.QueueId, specification.ServerId, (int)TaskStates.Cancel); using (IDbConnection connection = connectionFactory.CreateConnection()) { using (IDbCommand command = connectionFactory.CreateCommand(connection)) { command.CommandText = sqlCommand; using (IDataReader rdr = command.ExecuteReader()) { taskIds = new List <Int64>(); while (rdr.Read()) { Int64 id = (Int64)rdr["Id"]; taskIds.Add(id); } } } } return(taskIds.Count > 0); }
/// <summary> /// Get available task from the storage. /// </summary> /// <param name="specification">The <see cref="TaskRequestSpecification"/> instance.</param> /// <param name="taskModels">List of <see cref="WiseQueue.Core.Common.Models.Tasks.TaskStateModel"/> instances if it has been found</param> /// <returns>True if the list of TaskModel instances has been populated. Otherwise, false.</returns> public bool TryGetAvailableTask(TaskRequestSpecification specification, out List <TaskModel> taskModels) { if (specification == null) { throw new ArgumentNullException("specification"); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Declare @TempTable table ([Id] [bigint], "); stringBuilder.Append("[QueueId] [bigint], "); stringBuilder.Append("[ServerId] [bigint] NULL, "); stringBuilder.Append("[State] [smallint], "); stringBuilder.Append("[CompletedAt] [datetime] NULL, "); stringBuilder.Append("[ExecuteAt] [datetime] NOT NULL, "); stringBuilder.Append("[RepeatCrashCount] [int] NOT NULL, "); stringBuilder.Append("[InstanceType] [nvarchar](4000), "); stringBuilder.Append("[Method] [nvarchar](4000), "); stringBuilder.Append("[ParametersTypes] [nvarchar](4000), "); stringBuilder.AppendLine("[Arguments] [nvarchar](4000)); "); stringBuilder.AppendFormat("UPDATE TOP ({0}) {1}.{2} ", specification.MaxTasks, sqlSettings.WiseQueueDefaultSchema, taskTableName); stringBuilder.AppendFormat("SET State = {0}, ", (short)TaskStates.Pending); stringBuilder.AppendFormat("ServerId = {0} ", specification.ServerId); //stringBuilder.Append("RepeatCount = RepeatCount - 1 "); stringBuilder.Append("OUTPUT inserted.* INTO @TempTable "); stringBuilder.AppendFormat("Where (State = {0} ", (short)TaskStates.New); stringBuilder.AppendFormat("OR ( (State = {0} OR State = {1}) AND [ServerId] IS NULL)) ", (short)TaskStates.Pending, (short)TaskStates.Running); stringBuilder.AppendFormat("AND (QueueId = {0}) AND ([ExecuteAt] <= GETUTCDATE()) AND [RepeatCrashCount] > 0;", specification.QueueId); stringBuilder.AppendLine(); stringBuilder.AppendLine("SELECT * FROM @TempTable"); using (IDbConnection connection = connectionFactory.CreateConnection()) { using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) { using (IDbCommand command = connectionFactory.CreateCommand(connection, transaction)) { command.CommandText = stringBuilder.ToString(); using (IDataReader rdr = command.ExecuteReader()) { taskModels = new List <TaskModel>(); while (rdr.Read()) { Int64 id = (Int64)rdr["Id"]; Int64 queueId = (Int64)rdr["QueueId"]; Int64 serverId = (Int64)rdr["ServerId"]; TaskStates taskState = (TaskStates)(short)rdr["State"]; int repeatCrashCount = (int)rdr["RepeatCrashCount"]; string typeDetails = (string)rdr["InstanceType"]; string methodDetails = (string)rdr["Method"]; string parameterDetails = (string)rdr["ParametersTypes"]; string argumentDetails = (string)rdr["Arguments"]; TaskEntity taskEntity = new TaskEntity { Id = id, QueueId = queueId, ServerId = serverId, TaskState = taskState, InstanceType = typeDetails, Method = methodDetails, ParametersTypes = parameterDetails, Arguments = argumentDetails, RepeatCrashCount = repeatCrashCount }; TaskModel taskModel = taskConverter.Convert(taskEntity); taskModels.Add(taskModel); } } } if (taskModels.Count > 0) { transaction.Commit(); return(true); } } return(false); } }
/// <summary> /// Occurs when object should do its action. /// </summary> public void Execute() { if (taskManagerState == TaskManagerState.ClientOnly) { logger.WriteDebug("The server has client algorithm only."); return; } logger.WriteDebug("Searching for new tasks in available queue..."); IReadOnlyCollection <QueueModel> queues = queueManager.GetAvailableQueues(); foreach (QueueModel queueModel in queues) { Int64 queueId = queueModel.Id; Int64 serverId = serverManager.ServerId; TaskRequestSpecification specification = new TaskRequestSpecification(queueId, serverId, maxTasksPerQueue); List <TaskModel> taskModels; bool isReceived = taskDataContext.TryGetAvailableTask(specification, out taskModels); if (isReceived) { foreach (TaskModel taskModel in taskModels) { IRunningTask currentTask = null; try { currentTask = taskBuilder.Build(taskModel); lock (activeTasks) { activeTasks.Add(taskModel.Id, currentTask); } currentTask.OnCompletedEventHandler += OnCompletedEventHandler; currentTask.Execute(); //TODO: Provide global Cancelation Token. logger.WriteDebug("The task {0} has been received.", taskModel); } catch (Exception ex) { string msg = string.Format("There was an error during executing task: {0}.", taskModel); logger.WriteError(ex, msg); RestartTask(taskModel, msg, ex); } } } else { logger.WriteDebug("There is no new task in the storage."); } List <Int64> taskIds; isReceived = taskDataContext.TryGetCancelTasks(queueId, serverId, out taskIds); if (isReceived) { foreach (Int64 taskId in taskIds) { logger.WriteTrace("The task (id = {0}) has been marked for cancelation. Cancelling...", taskId); IRunningTask runningTask; lock (activeTasks) { if (activeTasks.ContainsKey(taskId) == false) { continue; } runningTask = activeTasks[taskId]; } logger.WriteTrace("The task ({0}) is running. Cancelling...", taskId); try { runningTask.Cancel(); } catch (Exception ex) { //TODO: Decide what to do. logger.WriteError("there was an exception during cancelation task.", ex); } logger.WriteTrace("The task has been marked for canceling."); } } else { logger.WriteDebug("There is no task for cancelation."); } } logger.WriteDebug("All tasks have been found if existed."); }