mirror of https://github.com/grpc/grpc.git
Merge pull request #3260 from nathanielmanistaatgoogle/protocol-objects
Plumb protocol objects through RPC Framework corepull/3281/head
commit
a4836ad77b
12 changed files with 319 additions and 24 deletions
@ -0,0 +1,176 @@ |
|||||||
|
# Copyright 2015, Google Inc. |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are |
||||||
|
# met: |
||||||
|
# |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above |
||||||
|
# copyright notice, this list of conditions and the following disclaimer |
||||||
|
# in the documentation and/or other materials provided with the |
||||||
|
# distribution. |
||||||
|
# * Neither the name of Google Inc. nor the names of its |
||||||
|
# contributors may be used to endorse or promote products derived from |
||||||
|
# this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
"""State and behavior for passing protocol objects in an operation.""" |
||||||
|
|
||||||
|
import collections |
||||||
|
import enum |
||||||
|
|
||||||
|
from grpc.framework.core import _constants |
||||||
|
from grpc.framework.core import _interfaces |
||||||
|
from grpc.framework.core import _utilities |
||||||
|
from grpc.framework.foundation import callable_util |
||||||
|
from grpc.framework.interfaces.base import base |
||||||
|
|
||||||
|
_EXCEPTION_LOG_MESSAGE = 'Exception delivering protocol object!' |
||||||
|
|
||||||
|
_LOCAL_FAILURE_OUTCOME = _utilities.Outcome( |
||||||
|
base.Outcome.Kind.LOCAL_FAILURE, None, None) |
||||||
|
|
||||||
|
|
||||||
|
class _Awaited( |
||||||
|
collections.namedtuple('_Awaited', ('kind', 'value',))): |
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Kind(enum.Enum): |
||||||
|
NOT_YET_ARRIVED = 'not yet arrived' |
||||||
|
ARRIVED = 'arrived' |
||||||
|
|
||||||
|
_NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None) |
||||||
|
_ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None) |
||||||
|
|
||||||
|
|
||||||
|
class _Transitory( |
||||||
|
collections.namedtuple('_Transitory', ('kind', 'value',))): |
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Kind(enum.Enum): |
||||||
|
NOT_YET_SEEN = 'not yet seen' |
||||||
|
PRESENT = 'present' |
||||||
|
GONE = 'gone' |
||||||
|
|
||||||
|
_NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None) |
||||||
|
_GONE = _Transitory(_Transitory.Kind.GONE, None) |
||||||
|
|
||||||
|
|
||||||
|
class _ProtocolManager(_interfaces.ProtocolManager): |
||||||
|
"""An implementation of _interfaces.ExpirationManager.""" |
||||||
|
|
||||||
|
def __init__( |
||||||
|
self, protocol_receiver, lock, pool, termination_manager, |
||||||
|
transmission_manager, expiration_manager): |
||||||
|
"""Constructor. |
||||||
|
|
||||||
|
Args: |
||||||
|
protocol_receiver: An _Awaited wrapping of the base.ProtocolReceiver to |
||||||
|
which protocol objects should be passed during the operation. May be |
||||||
|
of kind _Awaited.Kind.NOT_YET_ARRIVED if the customer's subscription is |
||||||
|
not yet known and may be of kind _Awaited.Kind.ARRIVED but with a value |
||||||
|
of None if the customer's subscription did not include a |
||||||
|
ProtocolReceiver. |
||||||
|
lock: The operation-wide lock. |
||||||
|
pool: A thread pool. |
||||||
|
termination_manager: The _interfaces.TerminationManager for the operation. |
||||||
|
transmission_manager: The _interfaces.TransmissionManager for the |
||||||
|
operation. |
||||||
|
expiration_manager: The _interfaces.ExpirationManager for the operation. |
||||||
|
""" |
||||||
|
self._lock = lock |
||||||
|
self._pool = pool |
||||||
|
self._termination_manager = termination_manager |
||||||
|
self._transmission_manager = transmission_manager |
||||||
|
self._expiration_manager = expiration_manager |
||||||
|
|
||||||
|
self._protocol_receiver = protocol_receiver |
||||||
|
self._context = _NOT_YET_SEEN |
||||||
|
|
||||||
|
def _abort_and_notify(self, outcome): |
||||||
|
if self._termination_manager.outcome is None: |
||||||
|
self._termination_manager.abort(outcome) |
||||||
|
self._transmission_manager.abort(outcome) |
||||||
|
self._expiration_manager.terminate() |
||||||
|
|
||||||
|
def _deliver(self, behavior, value): |
||||||
|
def deliver(): |
||||||
|
delivery_outcome = callable_util.call_logging_exceptions( |
||||||
|
behavior, _EXCEPTION_LOG_MESSAGE, value) |
||||||
|
if delivery_outcome.kind is callable_util.Outcome.Kind.RAISED: |
||||||
|
with self._lock: |
||||||
|
self._abort_and_notify(_LOCAL_FAILURE_OUTCOME) |
||||||
|
self._pool.submit( |
||||||
|
callable_util.with_exceptions_logged( |
||||||
|
deliver, _constants.INTERNAL_ERROR_LOG_MESSAGE)) |
||||||
|
|
||||||
|
def set_protocol_receiver(self, protocol_receiver): |
||||||
|
"""See _interfaces.ProtocolManager.set_protocol_receiver for spec.""" |
||||||
|
self._protocol_receiver = _Awaited(_Awaited.Kind.ARRIVED, protocol_receiver) |
||||||
|
if (self._context.kind is _Transitory.Kind.PRESENT and |
||||||
|
protocol_receiver is not None): |
||||||
|
self._deliver(protocol_receiver.context, self._context.value) |
||||||
|
self._context = _GONE |
||||||
|
|
||||||
|
def accept_protocol_context(self, protocol_context): |
||||||
|
"""See _interfaces.ProtocolManager.accept_protocol_context for spec.""" |
||||||
|
if self._protocol_receiver.kind is _Awaited.Kind.ARRIVED: |
||||||
|
if self._protocol_receiver.value is not None: |
||||||
|
self._deliver(self._protocol_receiver.value.context, protocol_context) |
||||||
|
self._context = _GONE |
||||||
|
else: |
||||||
|
self._context = _Transitory(_Transitory.Kind.PRESENT, protocol_context) |
||||||
|
|
||||||
|
|
||||||
|
def invocation_protocol_manager( |
||||||
|
subscription, lock, pool, termination_manager, transmission_manager, |
||||||
|
expiration_manager): |
||||||
|
"""Creates an _interfaces.ProtocolManager for invocation-side use. |
||||||
|
|
||||||
|
Args: |
||||||
|
subscription: The local customer's subscription to the operation. |
||||||
|
lock: The operation-wide lock. |
||||||
|
pool: A thread pool. |
||||||
|
termination_manager: The _interfaces.TerminationManager for the operation. |
||||||
|
transmission_manager: The _interfaces.TransmissionManager for the |
||||||
|
operation. |
||||||
|
expiration_manager: The _interfaces.ExpirationManager for the operation. |
||||||
|
""" |
||||||
|
if subscription.kind is base.Subscription.Kind.FULL: |
||||||
|
awaited_protocol_receiver = _Awaited( |
||||||
|
_Awaited.Kind.ARRIVED, subscription.protocol_receiver) |
||||||
|
else: |
||||||
|
awaited_protocol_receiver = _ARRIVED_AND_NONE |
||||||
|
return _ProtocolManager( |
||||||
|
awaited_protocol_receiver, lock, pool, termination_manager, |
||||||
|
transmission_manager, expiration_manager) |
||||||
|
|
||||||
|
|
||||||
|
def service_protocol_manager( |
||||||
|
lock, pool, termination_manager, transmission_manager, expiration_manager): |
||||||
|
"""Creates an _interfaces.ProtocolManager for service-side use. |
||||||
|
|
||||||
|
Args: |
||||||
|
lock: The operation-wide lock. |
||||||
|
pool: A thread pool. |
||||||
|
termination_manager: The _interfaces.TerminationManager for the operation. |
||||||
|
transmission_manager: The _interfaces.TransmissionManager for the |
||||||
|
operation. |
||||||
|
expiration_manager: The _interfaces.ExpirationManager for the operation. |
||||||
|
""" |
||||||
|
return _ProtocolManager( |
||||||
|
_NOT_YET_ARRIVED, lock, pool, termination_manager, transmission_manager, |
||||||
|
expiration_manager) |
Loading…
Reference in new issue