/// <summary> /// Obtains the first available task from the specified queue, and changes the client's /// state into TaskReserved. In that state, no new tasks can be reserved until the /// task's outcome is evident. /// </summary> /// <param name="queue"></param> /// <returns></returns> public TaskMessage Reserve(QueueName queue) { if (_state == RedisQueueState.TaskReserved) throw new TaskAlreadyReservedException("Cannot reserve multiple tasks at once."); if (string.IsNullOrEmpty(queue.ToString())) throw new NoQueueSpecifiedException( "Parameter <queue> is empty or null. Cannot retrieve task for no queue."); if (_taskMessageClient.Lists[queue.NameWhenPending].Count == 0) throw new QueueIsEmptyException("No tasks available in specified queue."); CurrentTask = _taskMessageClient.Lists[queue.NameWhenPending].RemoveStart(); _state = RedisQueueState.TaskReserved; _log.Info("Reserved task from [" + queue.NameWhenPending + "]"); _log.DebugFormat("Task Parameters: {0}", CurrentTask.Parameters); return CurrentTask; }
/// <summary> /// Marks the current task as failed, and regardless of the cycling setting, places it /// in the :failed queue. /// </summary> /// <param name="reason"></param> public void CriticalFail(string reason) { if (_state != RedisQueueState.TaskReserved) throw new NoTaskReservedException("No task has been reserved. Future failure not yet supported."); if (CurrentTask == null) throw new InvalidStateException("CurrentTask is null. Something's seriously off."); CurrentTask.Status = TaskStatus.Failed; CurrentTask.Reason = reason; CurrentTask.UpdatedOn = DateTime.Now; var targetQueue = new QueueName(CurrentTask.Queue).NameWhenFailed; _taskMessageClient.Lists[targetQueue].Add(CurrentTask); _log.Info("A task has failed. Moving to [" + targetQueue + "]."); _log.DebugFormat("Task Parameters: {0}", CurrentTask.Parameters); _state = RedisQueueState.Ready; }
/// <summary> /// Marks the currently reserved task as succeeded. /// </summary> /// <exception cref="InvalidStateException">CurrentTask is null. Something's seriously off.</exception> /// <exception cref="NoTaskReservedException">No task has been reserved. Future success not yet /// supported.</exception> public void Succeed() { if (_state != RedisQueueState.TaskReserved) throw new NoTaskReservedException( "No task has been reserved. Future success not yet supported."); if (CurrentTask == null) throw new InvalidStateException("CurrentTask is null. Something's seriously off."); CurrentTask.Status = TaskStatus.Succeeded; CurrentTask.UpdatedOn = DateTime.Now; if (!Settings.Default.PurgeSuccessfulTasks) { var queue = new QueueName(CurrentTask.Queue); _taskMessageClient.Lists[queue.NameWhenSucceeded].Add(CurrentTask); _log.Info("A task has succeeded. Moving to [" + queue.NameWhenSucceeded + "]."); } else { _log.Info("A task has succeeded and will be dropped."); } _log.DebugFormat("Task Parameters: {0}", CurrentTask.Parameters); _state = RedisQueueState.Ready; }
/// <summary> /// Marks the currently reserved task as failed. /// </summary> /// <param name="reason"></param> /// <exception cref="NoTaskReservedException">No task has been reserved. Future failure not yet /// supported.</exception> /// <exception cref="InvalidStateException">CurrentTask is null. Something's seriously off.</exception> public void Fail(string reason) { if (_state != RedisQueueState.TaskReserved) throw new NoTaskReservedException("No task has been reserved. Future failure not yet supported."); if (CurrentTask == null) throw new InvalidStateException("CurrentTask is null. Something's seriously off."); CurrentTask.Status = TaskStatus.Failed; CurrentTask.Reason = reason; CurrentTask.UpdatedOn = DateTime.Now; var queue = new QueueName(CurrentTask.Queue); var targetQueue = queue.NameWhenFailed; // If we support task cycling and the task should indeed be recycled, // place it to the end of the pending queue again. if (Settings.Default.TaskRecycling) if (Settings.Default.MaxTaskRetries == 0 || CurrentTask.Retries < Settings.Default.MaxTaskRetries) { targetQueue = queue.NameWhenPending; // If we support cycling, and we have a limit to how many times tasks // can be recycled, keep track of the number of retries. Do not remove this // lightly, since it can produce arithmetic overflows (<TaskMessage>.Retries is // an int, after all). if (CurrentTask.Retries < Settings.Default.MaxTaskRetries) CurrentTask.Retries++; } _taskMessageClient.Lists[targetQueue].Add(CurrentTask); _log.Info("A task has failed. Moving to [" + targetQueue + "]."); _log.DebugFormat("Task Parameters: {0}", CurrentTask.Parameters); _state = RedisQueueState.Ready; }