def get_task(self, task_uid): """Returns the task with the given task uid. Retrieves the task from the local pool if exists. Otherwise, fetches the task from the Queue server via POST :param task_uid: task's unique id :return: the task from the queue :rtype: queue.QueueTask """ # Search first in our local pool task_uid = get_task_uid(task_uid) task = filter(lambda t: t.task_uid == task_uid, self._tasks) if task: return copy.deepcopy(task[0]) # Ask the queue server (maybe we are searching for a failed) task_uid = get_task_uid(task_uid) try: task = self._post(task_uid) except HTTPError as e: # If not found (404), return None instead of exception to make this # utility to behave as server's if e.response.status_code != 404: raise e except Exception as e: raise e if not task: return None return to_task(task)
def delete(self, task): """Removes a task from the queue :param task: task's unique id (task_uid) or QueueTask object """ with self.__lock: task_uid = get_task_uid(task) self._delete(task_uid)
def has_task(self, task): """Returns whether the queue contains a given task :param task: task's unique id (task_uid) or QueueTask object :return: True if the queue contains the task :rtype: bool """ if self.get_task(get_task_uid(task)): return True return False
def timeout(self, task): """Notifies the queue that the processing of the task timed out. Sends a POST to the queue server and updates the local pool accordingly :param task: task's unique id (task_uid) or QueueTask object """ payload = {"task_uid": get_task_uid(task)} self._post("timeout", payload=payload) # Always sync on timeout (task might be re-queued or failed by server) self.sync()
def done(self, task): """Notifies the queue that the task has been processed successfully. Sends a POST to the queue server and removes the task from local pool :param task: task's unique id (task_uid) or QueueTask object """ # Tell the queue server the task is done task_uid = get_task_uid(task) payload = {"task_uid": task_uid} err = None try: self._post("done", payload=payload) except (ConnectionError, Timeout, TooManyRedirects) as e: err = "{}: {}".format(type(e).__name__, str(e)) except HTTPError as e: status = e.response.status_code or 500 if status < 500 or status >= 600: raise e message = e.response.json() or {} err = "{}: {}".format(status, message.get("message", str(e))) except APIError as e: if e.status < 500 or e.status >= 600: raise e err = "{}: {}".format(e.status, e.message) if err: # Not able to tell the queue server. Keep it locally so it can be # synchronized as soon as we have connectivity again logger.warn(err) capi.get_request().response.setStatus(200) task_uid = get_task_uid(task_uid) tasks = filter(lambda t: t.task_uid == task_uid, self._tasks) if tasks: task = tasks[0] else: self._tasks.append(task) task.update({"offline": "done"}) return # Remove from local pool self._tasks = filter(lambda t: t.task_uid != task_uid, self._tasks)
def fail(self, task, error_message=None): """Notifies the queue that the processing of the task failed. Sends a POST to the queue server and updates the local pool accordingly :param task: task's unique id (task_uid) or QueueTask object :param error_message: (Optional) the error/traceback """ task_uid = get_task_uid(task) payload = {"task_uid": task_uid, "error_message": error_message or ""} self._post("fail", payload=payload) # Always sync on fail (task might be re-queued or failed by server) self.sync()
def get(context, request, task_uid): # noqa """Returns a JSON representation of the task with the specified task uid """ # Get the task task = get_task(task_uid) # Digest the task and return zeo = get_post_zeo() task_uid = get_task_uid(task, default="none") logger.info("::server.get: {} [{}]".format(task_uid, zeo)) return get_task_info(task, complete=True)
def get_task(self, task_uid): """Returns the task with the given task uid :param task_uid: task's unique id :return: the task from the queue :rtype: queue.QueueTask """ task_uid = get_task_uid(task_uid) for task in self._tasks: if task.task_uid == task_uid: return copy.deepcopy(task) return None
def pop(context, request): # noqa """Pops the next task from the queue, if any. Popped task is no longer available in the queued tasks pool, but added in the running tasks pool """ # Get the consumer ID consumer_id = req.get_json().get("consumer_id") if not is_consumer_id(consumer_id): _fail(428, "No valid consumer id") # Pop the task from the queue task = qapi.get_queue().pop(consumer_id) # Return the task info task_uid = get_task_uid(task, default="<empty>") logger.info("::server.pop: {} [{}]".format(task_uid, consumer_id)) return get_task_info(task, complete=True)
def delete(self, task): """Removes a task from the queue. Sends a POST to the queue server and removes the task from the local pool of tasks :param task: task's unique id (task_uid) or QueueTask object """ task_uid = get_task_uid(task) payload = {"task_uid": task_uid} try: self._post("delete", payload=payload) except HTTPError as e: # If not found (404), return None instead of exception to make this # client utility to behave as server's if e.response.status_code != 404: raise e # Remove from our pool self._tasks = filter(lambda t: t.task_uid != task_uid, self._tasks)
def timeout(self, task): """Notifies the queue that the processing of the task timed out. Increases the max_seconds to spend with this task in 1.5 and removes the task from the running tasks. If remaining retries, the task is eventually re-queued. Is added to the pool of failed otherwise :param task: task's unique id (task_uid) or QueueTask object """ with self.__lock: # We do this dance because the task passed in is probably a copy, # but self._timeout expects a reference to self._tasks task_uid = get_task_uid(task) task = filter(lambda t: t.task_uid == task_uid, self._tasks) if not task: raise ValueError("Task is not in the queue") # Mark the task as failed by timeout self._timeout(task[0])
def fail(self, task, error_message=None): """Notifies the queue that the processing of the task failed. Removes the task from the running tasks. Is re-queued if there are remaining retries still. Otherwise, adds the task to the pool of failed :param task: task's unique id (task_uid) or QueueTask object :param error_message: (Optional) the error/traceback """ with self.__lock: # We do this dance because the task passed in is probably a copy, # but self._fail expects a reference to self._tasks task_uid = get_task_uid(task) task = filter(lambda t: t.task_uid == task_uid, self._tasks) if not task: raise ValueError("Task is not in the queue") # Label the task as failed self._fail(task[0], error_message=error_message)