Repository URL to install this package:
|
Version:
0.34.0 ▾
|
# Copyright 2017, Google LLC All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import time
import uuid
from six.moves import queue
__all__ = (
'QueueCallbackWorker',
'STOP',
)
_LOGGER = logging.getLogger(__name__)
# Helper thread stop indicator. This could be a sentinel object or None,
# but the sentinel object's ID can change if the process is forked, and
# None has the possibility of a user accidentally killing the helper
# thread.
STOP = uuid.uuid4()
def _get_many(queue_, max_items=None, max_latency=0):
"""Get multiple items from a Queue.
Gets at least one (blocking) and at most ``max_items`` items
(non-blocking) from a given Queue. Does not mark the items as done.
Args:
queue_ (~queue.Queue`): The Queue to get items from.
max_items (int): The maximum number of items to get. If ``None``, then
all available items in the queue are returned.
max_latency (float): The maximum number of seconds to wait for more
than one item from a queue. This number includes the time required
to retrieve the first item.
Returns:
Sequence[Any]: A sequence of items retrieved from the queue.
"""
start = time.time()
# Always return at least one item.
items = [queue_.get()]
while max_items is None or len(items) < max_items:
try:
elapsed = time.time() - start
timeout = max(0, max_latency - elapsed)
items.append(queue_.get(timeout=timeout))
except queue.Empty:
break
return items
class QueueCallbackWorker(object):
"""A helper that executes a callback for items sent in a queue.
Calls a blocking ``get()`` on the ``queue`` until it encounters
:attr:`STOP`.
Args:
queue (~queue.Queue): A Queue instance, appropriate for crossing the
concurrency boundary implemented by ``executor``. Items will
be popped off (with a blocking ``get()``) until :attr:`STOP`
is encountered.
callback (Callable[Sequence[Any], Any]): A callback that can process
items pulled off of the queue. Multiple items will be passed to
the callback in batches.
max_items (int): The maximum amount of items that will be passed to the
callback at a time.
max_latency (float): The maximum amount of time in seconds to wait for
additional items before executing the callback.
"""
def __init__(self, queue, callback, max_items=100, max_latency=0):
self.queue = queue
self._callback = callback
self.max_items = max_items
self.max_latency = max_latency
def __call__(self):
continue_ = True
while continue_:
items = _get_many(
self.queue,
max_items=self.max_items,
max_latency=self.max_latency)
# If stop is in the items, process all items up to STOP and then
# exit.
try:
items = items[:items.index(STOP)]
continue_ = False
except ValueError:
pass
# Run the callback. If any exceptions occur, log them and
# continue.
try:
self._callback(items)
except Exception as exc:
_LOGGER.error('%s: %s', exc.__class__.__name__, exc)
_LOGGER.debug('Exiting the QueueCallbackWorker.')