/// <summary> /// Adds a task to the queue specified in the task itself and sends a message to /// the associated channel, notifying any listeners. /// </summary> /// <param name="t"></param> public void Enqueue(TaskMessage t) { if (string.IsNullOrEmpty(t.Queue)) throw new NoQueueSpecifiedException( "TaskMessage.Queue is empty or null. Cannot append task to queue."); var queue = new QueueName(t.Queue); _taskMessageClient.Lists[queue.NameWhenPending].Add(t); SendMessage(QueueSystemMessages.TaskAvailable.ToString(), queue); _log.Info("New task in [" + queue.NameWhenPending + "]"); _log.DebugFormat("Task Parameters: {0}", t.Parameters); }
/// <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; }
public QueueSubscriber() { Queue = new QueueName(Settings.Default.Queue); Client = new RedisQueueClient(); }
/// <summary> /// Removes a task with a specific task identifier. /// </summary> /// <param name="task"></param> public void RemoveTask(TaskMessage task) { var queueName = new QueueName(task.Queue); removeTask(queueName.NameWhenPending, task); removeTask(queueName.NameWhenFailed, task); removeTask(queueName.NameWhenSucceeded, task); }
/// <summary> /// Sends a message to the channel associated with a specific queue. /// </summary> /// <param name="message"></param> /// <param name="queue"></param> public void SendMessage(string message, QueueName queue) { _client.PublishMessage(queue.ChannelName, message); }
/// <summary> /// Returns all succeeded tasks. /// </summary> /// <param name="queue"></param> /// <returns></returns> public IList<TaskMessage> SucceededTasks(QueueName queue) { if (string.IsNullOrEmpty(queue.ToString())) throw new NoQueueSpecifiedException( "Parameter <queue> is empty or null. Cannot retrieve task for no queue."); return _taskMessageClient.Lists[queue.NameWhenSucceeded]; }
/// <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 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 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; }