def _enqueue(self, local_prof):
        """
        **Purpose**: This is the function that is run in the enqueue thread. This function extracts Tasks from the
        copy of workflow that exists in the WFprocessor object and pushes them to the queues in the pending_q list.
        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('enqueue-thread started', uid=self._uid)
            self._logger.info('enqueue-thread started')

            # Acquire a connection+channel to the rmq server
            mq_connection = pika.BlockingConnection(
                pika.ConnectionParameters(host=self._mq_hostname, port=self._port))
            mq_channel = mq_connection.channel()

            last = time.time()
            while not self._enqueue_thread_terminate.is_set():

                '''
                We iterate through all pipelines to collect tasks from
                stages that are pending scheduling. Once collected, these tasks
                will be communicated to the tmgr in bulk.
                '''

                workload = []
                scheduled_stages = []

                for pipe in self._workflow:

                    with pipe.lock:

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

                            # Test if the pipeline is already in the final state
                            if pipe.state in states.FINAL:
                                continue

                            elif pipe.state == states.INITIAL:

                                # Set state of pipeline to SCHEDULING if it is in INITIAL
                                transition(obj=pipe,
                                           obj_type='Pipeline',
                                           new_state=states.SCHEDULING,
                                           channel=mq_channel,
                                           queue='%s-enq-to-sync' % self._sid,
                                           profiler=local_prof,
                                           logger=self._logger)

                            executable_stage = pipe.stages[pipe.current_stage - 1]

                            if not executable_stage.uid:
                                executable_stage.parent_pipeline['uid'] = pipe.uid
                                executable_stage.parent_pipeline['name'] = pipe.name
                                executable_stage._assign_uid(self._sid)

                            if executable_stage.state in [states.INITIAL, states.SCHEDULED]:

                                if executable_stage.state == states.INITIAL:

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

                                executable_tasks = executable_stage.tasks

                                for executable_task in executable_tasks:

                                    if (executable_task.state == states.INITIAL)or \
                                            ((executable_task.state == states.FAILED)and(self._resubmit_failed)):

                                        # Set state of Tasks in current Stage to SCHEDULING
                                        transition(obj=executable_task,
                                                   obj_type='Task',
                                                   new_state=states.SCHEDULING,
                                                   channel=mq_channel,
                                                   queue='%s-enq-to-sync' % self._sid,
                                                   profiler=local_prof,
                                                   logger=self._logger)

                                        # task_as_dict = json.dumps(executable_task.to_dict())
                                        workload.append(executable_task)

                                        if executable_stage not in scheduled_stages:
                                            scheduled_stages.append(
                                                executable_stage)

                if workload:

                    # Put the task on one of the pending_queues
                    workload_as_dict = list()
                    for task in workload:
                        workload_as_dict.append(task.to_dict())
                    workload_as_dict = json.dumps(workload_as_dict)

                    mq_channel.basic_publish(exchange='',
                                             routing_key=self._pending_queue[0],
                                             body=workload_as_dict
                                             # properties=pika.BasicProperties(
                                             # make message persistent
                                             # delivery_mode = 2)
                                             )

                    for task in workload:

                        # Set state of Tasks in current Stage to SCHEDULED
                        transition(obj=task,
                                   obj_type='Task',
                                   new_state=states.SCHEDULED,
                                   channel=mq_channel,
                                   queue='%s-enq-to-sync' % self._sid,
                                   profiler=local_prof,
                                   logger=self._logger)

                        self._logger.debug(
                            'Task %s published to pending queue' % task.uid)

                if scheduled_stages:
                    for executable_stage in scheduled_stages:

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

                # 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

            self._logger.info('Enqueue thread terminated')
            mq_connection.close()

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

        except KeyboardInterrupt:

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

            mq_connection.close()

            raise KeyboardInterrupt

        except Exception, ex:

            self._logger.exception('Error in enqueue-thread: %s' % ex)
            try:
                mq_connection.close()
            except Exception as ex:
                self._logger.warning('mq_connection not created, %s' % ex)

            raise
**Purpose**: This is the function that is run in the enqueue thread. This function extracts Tasks from the
        copy of workflow that exists in the WFprocessor object and pushes them to the queues in the pending_q list.
        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.