def _dequeue(self, local_prof):
        """
        **Purpose**: This is the function that is run in the dequeue thread. This function extracts Tasks from the
        completed queus and updates the copy of workflow that exists in the WFprocessor object.
        Since this thread works on the copy of the workflow, every state update to the Task, Stage and Pipeline is
        communicated back to the AppManager (master process) via the 'sync_with_master' function that has dedicated
        queues to communicate with the master.

        Details: Termination condition of this thread is set by the wfp process.
        """

        try:

            local_prof.prof('dequeue-thread started', uid=self._uid)
            self._logger.info('Dequeue thread started')

            mq_connection = pika.BlockingConnection(
                pika.ConnectionParameters(host=self._mq_hostname, port=self._port))
            mq_channel = mq_connection.channel()

            last = time.time()

            while not self._dequeue_thread_terminate.is_set():

                try:

                    method_frame, header_frame, body = mq_channel.basic_get(
                        queue=self._completed_queue[0])

                    if body:

                        # Get task from the message
                        completed_task = Task()
                        completed_task.from_dict(json.loads(body))
                        self._logger.info(
                            'Got finished task %s from queue' % (completed_task.uid))

                        transition(obj=completed_task,
                                   obj_type='Task',
                                   new_state=states.DEQUEUEING,
                                   channel=mq_channel,
                                   queue='%s-deq-to-sync' % self._sid,
                                   profiler=local_prof,
                                   logger=self._logger)

                        # Traverse the entire workflow to find out the correct Task
                        for pipe in self._workflow:

                            with pipe.lock:

                                if ((not pipe.completed) and (not pipe.state == states.SUSPENDED)):

                                    if completed_task.parent_pipeline['uid'] == pipe.uid:

                                        self._logger.debug(
                                            'Found parent pipeline: %s' % pipe.uid)

                                        for stage in pipe.stages:

                                            if completed_task.parent_stage['uid'] == stage.uid:
                                                self._logger.debug(
                                                    'Found parent stage: %s' % (stage.uid))

                                                transition(obj=completed_task,
                                                           obj_type='Task',
                                                           new_state=states.DEQUEUED,
                                                           channel=mq_channel,
                                                           queue='%s-deq-to-sync' % self._sid,
                                                           profiler=local_prof,
                                                           logger=self._logger)

                                                if not completed_task.exit_code:
                                                    completed_task.state = states.DONE
                                                else:
                                                    completed_task.state = states.FAILED

                                                for task in stage.tasks:

                                                    if task.uid == completed_task.uid:
                                                        task.state = str(
                                                            completed_task.state)

                                                        if (task.state == states.FAILED) and (self._resubmit_failed):
                                                            task.state = states.INITIAL

                                                        transition(obj=task,
                                                                   obj_type='Task',
                                                                   new_state=task.state,
                                                                   channel=mq_channel,
                                                                   queue='%s-deq-to-sync' % self._sid,
                                                                   profiler=local_prof,
                                                                   logger=self._logger)

                                                        if stage._check_stage_complete():

                                                            transition(obj=stage,
                                                                       obj_type='Stage',
                                                                       new_state=states.DONE,
                                                                       channel=mq_channel,
                                                                       queue='%s-deq-to-sync' % self._sid,
                                                                       profiler=local_prof,
                                                                       logger=self._logger)

                                                            # Check if Stage has a post-exec that needs to be
                                                            # executed

                                                            if stage.post_exec:

                                                                try:

                                                                    self._logger.info('Executing post-exec for stage %s'
                                                                                    % stage.uid)
                                                                    self._prof.prof('Adap: executing post-exec',
                                                                                    uid=self._uid)

                                                                    stage.post_exec()

                                                                    self._logger.info(
                                                                        'Post-exec executed for stage %s' % stage.uid)
                                                                    self._prof.prof(
                                                                        'Adap: post-exec executed', uid=self._uid)

                                                                except Exception, ex:
                                                                    self._logger.exception('Execution failed in post_exec of stage %s' % stage.uid)
                                                                    raise

                                                            pipe._increment_stage()

                                                            if pipe.completed:

                                                                transition(obj=pipe,
                                                                           obj_type='Pipeline',
                                                                           new_state=states.DONE,
                                                                           channel=mq_channel,
                                                                           queue='%s-deq-to-sync' % self._sid,
                                                                           profiler=local_prof,
                                                                           logger=self._logger)

                                                        # Found the task and processed it -- no more iterations needed
                                                        break

                                                # Found the stage and processed it -- no more iterations neeeded
                                                break

                                        # Found the pipeline and processed it -- no more iterations neeeded
                                        break

                        mq_channel.basic_ack(
                            delivery_tag=method_frame.delivery_tag)

                    # Appease pika cos it thinks the connection is dead
                    now = time.time()
                    if now - last >= self._rmq_ping_interval:
                        mq_connection.process_data_events()
                        last = now

                except Exception, ex:
                    self._logger.exception(
                        'Unable to receive message from completed queue: %s' % ex)
                    raise

            self._logger.info('Terminated dequeue thread')
            mq_connection.close()

            local_prof.prof('terminating dequeue-thread', uid=self._uid)

        except KeyboardInterrupt:

            self._logger.exception('Execution interrupted by user (you probably hit Ctrl+C), ' +
                               'trying to exit gracefully...')

            mq_connection.close()

            raise KeyboardInterrupt

        except Exception, ex:
            self._logger.exception('Error in dequeue-thread: %s' % ex)

            try:
                mq_connection.close()
            except:
                self._logger.warning('mq_connection not created')

            raise EnTKError(ex)