示例#1
0
 def test_getnowait(self):
     with patch.object(self.m, "__len__") as mock_len:
         mock_len.return_value = 1
         q = iodict.DurableQueue(path="/not/a/path")
         with patch.object(q._count, "acquire",
                           autospec=True) as mock_acquire:
             with patch.object(q._queue, "popitem") as mock_popitem:
                 mock_popitem.return_value = "test"
                 self.assertEqual(q.get_nowait(), "test")
                 mock_acquire.assert_called_with(False, None)
示例#2
0
    def job_q_processor(self, q_processes, lock=None):
        """Process a given work queue.

        The defined `queue` is processed. The `processes` arg allows this
        method to spawn N processes.

        :param q_processes: Queue object
        :type q_processes: Object
        :param lock: Locking object, used if a component requires it.
        :type lock: Object
        """

        def _get_pending_bypass_threads(parents):
            """Return the current non-bypass thread objects.

            :param parents: Dictionary of all parent objects.
            :type parents: Dictionary
            :returns: List
            """

            return [
                i["t"].name
                for i in parents.values()
                if i["bypass"]
                and not i["t"].is_alive()
                and i["t"].ident is None
            ]

        def _get_pending_threads(parents):
            """Return the current non-bypass thread objects.

            :param parents: Dictionary of all parent objects.
            :type parents: Dictionary
            :returns: List
            """

            return [
                i["t"].name
                for i in parents.values()
                if not i["bypass"]
                and not i["t"].is_alive()
                and i["t"].ident is None
            ]

        def _get_thread_count(parents):
            """Return the current non-bypass thread count.

            :param parents: Dictionary of all parent objects.
            :type parents: Dictionary
            :returns: Integer
            """

            return len(
                [
                    True
                    for i in parents.values()
                    if not i["bypass"] and i["t"].is_alive()
                ]
            )

        if not lock:
            lock = self.driver.get_lock()

        parent_tracker_recover = iodict.DurableQueue(
            path=os.path.join(self.args.cache_path, "parent_tracker"),
            lock=lock,
        )
        parent_tracker = collections.OrderedDict()
        for item in parent_tracker_recover.getter():
            k, v = item
            q = self.driver.get_queue(name=k)
            parent_tracker[k] = dict(t=None, q=q, bypass=v)
            parent_tracker[k]["t"] = self.driver.thread_processor(
                target=self.q_processor,
                kwargs=dict(
                    queue=parent_tracker[k]["q"],
                    lock=lock,
                ),
                name=k,
                daemon=True,
            )

        while not q_processes.empty() or parent_tracker:
            try:
                (
                    component_kwargs,
                    command,
                    info,
                ) = q_processes.get_nowait()
            except ValueError as e:
                self.log.critical("Queue object value error [ %s ]", str(e))
            except Exception:
                sleep_interval = 0.1
            else:
                sleep_interval = 0.001
                lower_command = command.lower()
                job = component_kwargs["job"]
                self.log.debug("Received job_id [ %s ]", job["job_id"])
                # NOTE(cloudnull): If the command is queuesentinel purge all
                #                  queued items. This is on the ONE component
                #                  where we intercept and react outside of
                #                  the component structure.
                if lower_command == "queuesentinel":
                    count = 0
                    for value in list(parent_tracker.values()):
                        count = 0
                        for item in value["q"].getter():
                            _kwargs, _command, _ = item
                            self.q_return.put(
                                (
                                    None,
                                    None,
                                    False,
                                    "Omitted due to sentinel from {}".format(
                                        job["job_id"]
                                    ),
                                    _kwargs["job"],
                                    _command,
                                    0,
                                    None,
                                )
                            )
                            count += 1
                    self.log.info(
                        "Purged %s items from the work queues", count
                    )

                if job.get("parent_async_bypass") is True:
                    _q_name = "q_bypass_{}".format(
                        job.get("parent_id", job["job_id"])
                    )
                elif job.get("parent_async") is True:
                    _q_name = "q_async_{}".format(
                        job.get("parent_id", job["job_id"])
                    )
                else:
                    _q_name = "q_general"

                if _q_name not in parent_tracker:
                    parent_tracker.setdefault(
                        _q_name,
                        dict(
                            t=None,
                            q=self.driver.get_queue(name=_q_name),
                            bypass=job.get("parent_async_bypass", False),
                        ),
                    )
                    parent_tracker[_q_name][
                        "t"
                    ] = self.driver.thread_processor(
                        target=self.q_processor,
                        kwargs=dict(
                            queue=parent_tracker[_q_name]["q"],
                            lock=lock,
                        ),
                        name=_q_name,
                        daemon=True,
                    )
                    self.log.info("Parent queue [ %s ] created.", _q_name)

                parent_tracker[_q_name]["q"].put(
                    (component_kwargs, command, info)
                )

            for t in _get_pending_bypass_threads(parents=parent_tracker):
                self.log.info("Starting bypass process [ %s ]", t)
                parent_tracker[t]["t"].start()

            while _get_thread_count(parents=parent_tracker) <= self.cpu_count:
                for t in _get_pending_threads(parents=parent_tracker):
                    self.log.info("Starting process [ %s ]", t)
                    parent_tracker[t]["t"].start()
                else:
                    break

            for key, value in list(parent_tracker.items()):
                if value["t"].is_alive() or value["t"].ident is None:
                    continue
                else:
                    timestamp = time.time()
                    timeout = timestamp - value.get("timeout", timestamp) > 5
                    if value["q"].empty() and timeout:
                        self.terminate_process(process=value["t"])
                        parent_tracker.pop(key)
                        self.log.info("Pruned parent [ %s ]", key)
                    elif not value["q"].empty():
                        self.log.warning(
                            "Parent thread was terminated but the queue [ %s ]"
                            " had items in it, respawning",
                            key,
                        )
                        parent_tracker[key].pop("timeout", None)
                        parent_tracker[key][
                            "t"
                        ] = self.driver.thread_processor(
                            target=self.q_processor,
                            kwargs=dict(
                                queue=parent_tracker[key]["q"],
                                lock=lock,
                            ),
                            name=key,
                            daemon=True,
                        )
                    elif "timeout" not in parent_tracker[key]:
                        self.log.info("Starting to prune parent [ %s ]", key)
                        parent_tracker[key]["timeout"] = timestamp

            if self.driver.event.is_set():
                for k, v in parent_tracker.items():
                    v["q"].flush()
                    parent_tracker_recover.put((k, v["bypass"]))
                return

            time.sleep(sleep_interval)
示例#3
0
 def test_putnowait(self):
     q = iodict.DurableQueue(path="/not/a/path")
     with patch.object(self.m, "_queue") as mock__queue:
         mock__queue.return_value = dict()
         with patch("builtins.open", unittest.mock.mock_open()):
             q.put_nowait("test")
示例#4
0
 def test_get_timeout(self):
     q = iodict.DurableQueue(path="/not/a/path")
     with self.assertRaises(queue.Empty):
         q.get(timeout=0.1)
示例#5
0
 def test_get_negative_timeout(self):
     q = iodict.DurableQueue(path="/not/a/path")
     with self.assertRaises(ValueError):
         q.get(timeout=-1)
示例#6
0
 def test_empty(self):
     q = iodict.DurableQueue(path="/not/a/path")
     self.assertEqual(q.empty(), True)
     with patch.object(self.m, "__len__"):
         self.assertEqual(q.empty(), False)
示例#7
0
 def test_close_missing(self):
     q = iodict.DurableQueue(path="/not/a/path")
     with patch("os.rmdir") as mock_rmdir:
         mock_rmdir.side_effect = FileNotFoundError
         q.close()
示例#8
0
 def test_close(self):
     q = iodict.DurableQueue(path="/not/a/path")
     with patch("os.rmdir") as mock_rmdir:
         q.close()