Source code for google.cloud.pubsub_v1.futures
# 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.
from __future__ import absolute_import
import threading
import uuid
import google.api_core.future
from google.cloud.pubsub_v1.publisher import exceptions
class Future(google.api_core.future.Future):
"""Encapsulation of the asynchronous execution of an action.
This object is returned from asychronous Pub/Sub calls, and is the
interface to determine the status of those calls.
This object should not be created directly, but is returned by other
methods in this library.
Args:
completed (Optional[Any]): An event, with the same interface as
:class:`threading.Event`. This is provided so that callers
with different concurrency models (e.g. ``threading`` or
``multiprocessing``) can supply an event that is compatible
with that model. The ``wait()`` and ``set()`` methods will be
used. If this argument is not provided, then a new
:class:`threading.Event` will be created and used.
"""
# 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
# actually being a result.
_SENTINEL = uuid.uuid4()
def __init__(self, completed=None):
self._result = self._SENTINEL
self._exception = self._SENTINEL
self._callbacks = []
if completed is None:
completed = threading.Event()
self._completed = completed
[docs] def cancel(self):
"""Actions in Pub/Sub generally may not be canceled.
This method always returns False.
"""
return False
[docs] def cancelled(self):
"""Actions in Pub/Sub generally may not be canceled.
This method always returns False.
"""
return False
[docs] def running(self):
"""Actions in Pub/Sub generally may not be canceled.
Returns:
bool: ``True`` if this method has not yet completed, or
``False`` if it has completed.
"""
if self.done():
return False
return True
[docs] def done(self):
"""Return True the future is done, False otherwise.
This still returns True in failure cases; checking :meth:`result` or
:meth:`exception` is the canonical way to assess success or failure.
"""
return self._exception != self._SENTINEL or self._result != self._SENTINEL
def result(self, timeout=None):
"""Resolve the future and return a value where appropriate.
Args:
timeout (Union[int, float]): The number of seconds before this call
times out and raises TimeoutError.
Raises:
concurrent.futures.TimeoutError: If the request times out.
Exception: For undefined exceptions in the underlying
call execution.
"""
# Attempt to get the exception if there is one.
# If there is not one, then we know everything worked, and we can
# return an appropriate value.
err = self.exception(timeout=timeout)
if err is None:
return self._result
raise err
[docs] def exception(self, timeout=None):
"""Return the exception raised by the call, if any.
Args:
timeout (Union[int, float]): The number of seconds before this call
times out and raises TimeoutError.
Raises:
concurrent.futures.TimeoutError: If the request times out.
Returns:
Exception: The exception raised by the call, if any.
"""
# Wait until the future is done.
if not self._completed.wait(timeout=timeout):
raise exceptions.TimeoutError("Timed out waiting for result.")
# If the batch completed successfully, this should return None.
if self._result != self._SENTINEL:
return None
# Okay, this batch had an error; this should return it.
return self._exception
[docs] def add_done_callback(self, callback):
"""Attach the provided callable to the future.
The provided function is called, with this future as its only argument,
when the future finishes running.
Args:
callback (Callable): The function to call.
Returns:
None
"""
if self.done():
return callback(self)
self._callbacks.append(callback)
[docs] def set_result(self, result):
"""Set the result of the future to the provided result.
Args:
result (Any): The result
"""
# Sanity check: A future can only complete once.
if self.done():
raise RuntimeError("set_result can only be called once.")
# Set the result and trigger the future.
self._result = result
self._trigger()
[docs] def set_exception(self, exception):
"""Set the result of the future to the given exception.
Args:
exception (:exc:`Exception`): The exception raised.
"""
# Sanity check: A future can only complete once.
if self.done():
raise RuntimeError("set_exception can only be called once.")
# Set the exception and trigger the future.
self._exception = exception
self._trigger()
def _trigger(self):
"""Trigger all callbacks registered to this Future.
This method is called internally by the batch once the batch
completes.
Args:
message_id (str): The message ID, as a string.
"""
self._completed.set()
for callback in self._callbacks:
callback(self)