mirror of https://github.com/grpc/grpc.git
Merge pull request #2951 from nathanielmanistaatgoogle/base-interface
The (new) base interface of RPC Frameworkpull/2963/head
commit
d6225ee6eb
3 changed files with 382 additions and 0 deletions
@ -0,0 +1,30 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
|
@ -0,0 +1,273 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
"""The base interface of RPC Framework.""" |
||||||
|
|
||||||
|
import abc |
||||||
|
import enum |
||||||
|
|
||||||
|
# abandonment is referenced from specification in this module. |
||||||
|
from grpc.framework.foundation import abandonment # pylint: disable=unused-import |
||||||
|
|
||||||
|
|
||||||
|
class NoSuchMethodError(Exception): |
||||||
|
"""Indicates that an unrecognized operation has been called.""" |
||||||
|
|
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Outcome(enum.Enum): |
||||||
|
"""Operation outcomes.""" |
||||||
|
|
||||||
|
COMPLETED = 'completed' |
||||||
|
CANCELLED = 'cancelled' |
||||||
|
EXPIRED = 'expired' |
||||||
|
LOCAL_SHUTDOWN = 'local shutdown' |
||||||
|
REMOTE_SHUTDOWN = 'remote shutdown' |
||||||
|
RECEPTION_FAILURE = 'reception failure' |
||||||
|
TRANSMISSION_FAILURE = 'transmission failure' |
||||||
|
LOCAL_FAILURE = 'local failure' |
||||||
|
REMOTE_FAILURE = 'remote failure' |
||||||
|
|
||||||
|
|
||||||
|
class Completion(object): |
||||||
|
"""An aggregate of the values exchanged upon operation completion. |
||||||
|
|
||||||
|
Attributes: |
||||||
|
terminal_metadata: A terminal metadata value for the operaton. |
||||||
|
code: A code value for the operation. |
||||||
|
message: A message value for the operation. |
||||||
|
""" |
||||||
|
__metaclass__ = abc.ABCMeta |
||||||
|
|
||||||
|
|
||||||
|
class OperationContext(object): |
||||||
|
"""Provides operation-related information and action.""" |
||||||
|
__metaclass__ = abc.ABCMeta |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def outcome(self): |
||||||
|
"""Indicates the operation's outcome (or that the operation is ongoing). |
||||||
|
|
||||||
|
Returns: |
||||||
|
None if the operation is still active or the Outcome value for the |
||||||
|
operation if it has terminated. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def add_termination_callback(self, callback): |
||||||
|
"""Adds a function to be called upon operation termination. |
||||||
|
|
||||||
|
Args: |
||||||
|
callback: A callable to be passed an Outcome value on operation |
||||||
|
termination. |
||||||
|
|
||||||
|
Returns: |
||||||
|
None if the operation has not yet terminated and the passed callback will |
||||||
|
later be called when it does terminate, or if the operation has already |
||||||
|
terminated an Outcome value describing the operation termination and the |
||||||
|
passed callback will not be called as a result of this method call. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def time_remaining(self): |
||||||
|
"""Describes the length of allowed time remaining for the operation. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A nonnegative float indicating the length of allowed time in seconds |
||||||
|
remaining for the operation to complete before it is considered to have |
||||||
|
timed out. Zero is returned if the operation has terminated. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def cancel(self): |
||||||
|
"""Cancels the operation if the operation has not yet terminated.""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def fail(self, exception): |
||||||
|
"""Indicates that the operation has failed. |
||||||
|
|
||||||
|
Args: |
||||||
|
exception: An exception germane to the operation failure. May be None. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
class Operator(object): |
||||||
|
"""An interface through which to participate in an operation.""" |
||||||
|
__metaclass__ = abc.ABCMeta |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def advance( |
||||||
|
self, initial_metadata=None, payload=None, completion=None, |
||||||
|
allowance=None): |
||||||
|
"""Progresses the operation. |
||||||
|
|
||||||
|
Args: |
||||||
|
initial_metadata: An initial metadata value. Only one may ever be |
||||||
|
communicated in each direction for an operation, and they must be |
||||||
|
communicated no later than either the first payload or the completion. |
||||||
|
payload: A payload value. |
||||||
|
completion: A Completion value. May only ever be non-None once in either |
||||||
|
direction, and no payloads may be passed after it has been communicated. |
||||||
|
allowance: A positive integer communicating the number of additional |
||||||
|
payloads allowed to be passed by the remote side of the operation. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
class Subscription(object): |
||||||
|
"""Describes customer code's interest in values from the other side. |
||||||
|
|
||||||
|
Attributes: |
||||||
|
kind: A Kind value describing the overall kind of this value. |
||||||
|
termination_callback: A callable to be passed the Outcome associated with |
||||||
|
the operation after it has terminated. Must be non-None if kind is |
||||||
|
Kind.TERMINATION_ONLY. Must be None otherwise. |
||||||
|
allowance: A callable behavior that accepts positive integers representing |
||||||
|
the number of additional payloads allowed to be passed to the other side |
||||||
|
of the operation. Must be None if kind is Kind.FULL. Must not be None |
||||||
|
otherwise. |
||||||
|
operator: An Operator to be passed values from the other side of the |
||||||
|
operation. Must be non-None if kind is Kind.FULL. Must be None otherwise. |
||||||
|
""" |
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Kind(enum.Enum): |
||||||
|
|
||||||
|
NONE = 'none' |
||||||
|
TERMINATION_ONLY = 'termination only' |
||||||
|
FULL = 'full' |
||||||
|
|
||||||
|
|
||||||
|
class Servicer(object): |
||||||
|
"""Interface for service implementations.""" |
||||||
|
__metaclass__ = abc.ABCMeta |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def service(self, group, method, context, output_operator): |
||||||
|
"""Services an operation. |
||||||
|
|
||||||
|
Args: |
||||||
|
group: The group identifier of the operation to be serviced. |
||||||
|
method: The method identifier of the operation to be serviced. |
||||||
|
context: An OperationContext object affording contextual information and |
||||||
|
actions. |
||||||
|
output_operator: An Operator that will accept output values of the |
||||||
|
operation. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A Subscription via which this object may or may not accept more values of |
||||||
|
the operation. |
||||||
|
|
||||||
|
Raises: |
||||||
|
NoSuchMethodError: If this Servicer does not handle operations with the |
||||||
|
given group and method. |
||||||
|
abandonment.Abandoned: If the operation has been aborted and there no |
||||||
|
longer is any reason to service the operation. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
class End(object): |
||||||
|
"""Common type for entry-point objects on both sides of an operation.""" |
||||||
|
__metaclass__ = abc.ABCMeta |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def start(self): |
||||||
|
"""Starts this object's service of operations.""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def stop_gracefully(self): |
||||||
|
"""Gracefully stops this object's service of operations. |
||||||
|
|
||||||
|
Operations in progress will be allowed to complete, and this method blocks |
||||||
|
until all of them have. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def stop_immediately(self): |
||||||
|
"""Immediately stops this object's service of operations. |
||||||
|
|
||||||
|
Operations in progress will not be allowed to complete. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def operate( |
||||||
|
self, group, method, subscription, timeout, initial_metadata=None, |
||||||
|
payload=None, completion=None): |
||||||
|
"""Commences an operation. |
||||||
|
|
||||||
|
Args: |
||||||
|
group: The group identifier of the invoked operation. |
||||||
|
method: The method identifier of the invoked operation. |
||||||
|
subscription: A Subscription to which the results of the operation will be |
||||||
|
passed. |
||||||
|
timeout: A length of time in seconds to allow for the operation. |
||||||
|
initial_metadata: An initial metadata value to be sent to the other side |
||||||
|
of the operation. May be None if the initial metadata will be later |
||||||
|
passed via the returned operator or if there will be no initial metadata |
||||||
|
passed at all. |
||||||
|
payload: An initial payload for the operation. |
||||||
|
completion: A Completion value indicating the end of transmission to the |
||||||
|
other side of the operation. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A pair of objects affording information about the operation and action |
||||||
|
continuing the operation. The first element of the returned pair is an |
||||||
|
OperationContext for the operation and the second element of the |
||||||
|
returned pair is an Operator to which operation values not passed in |
||||||
|
this call should later be passed. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def operation_stats(self): |
||||||
|
"""Reports the number of terminated operations broken down by outcome. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A dictionary from Outcome value to an integer identifying the number |
||||||
|
of operations that terminated with that outcome. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def add_idle_action(self, action): |
||||||
|
"""Adds an action to be called when this End has no ongoing operations. |
||||||
|
|
||||||
|
Args: |
||||||
|
action: A callable that accepts no arguments. |
||||||
|
""" |
||||||
|
raise NotImplementedError() |
@ -0,0 +1,79 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
"""Utilities for use with the base interface of RPC Framework.""" |
||||||
|
|
||||||
|
import collections |
||||||
|
|
||||||
|
from grpc.framework.interfaces.base import base |
||||||
|
|
||||||
|
|
||||||
|
class _Completion( |
||||||
|
base.Completion, |
||||||
|
collections.namedtuple( |
||||||
|
'_Completion', ('terminal_metadata', 'code', 'message',))): |
||||||
|
"""A trivial implementation of base.Completion.""" |
||||||
|
|
||||||
|
|
||||||
|
class _Subscription( |
||||||
|
base.Subscription, |
||||||
|
collections.namedtuple( |
||||||
|
'_Subscription', |
||||||
|
('kind', 'termination_callback', 'allowance', 'operator',))): |
||||||
|
"""A trivial implementation of base.Subscription.""" |
||||||
|
|
||||||
|
_NONE_SUBSCRIPTION = _Subscription( |
||||||
|
base.Subscription.Kind.NONE, None, None, None) |
||||||
|
|
||||||
|
|
||||||
|
def completion(terminal_metadata, code, message): |
||||||
|
"""Creates a base.Completion aggregating the given operation values. |
||||||
|
|
||||||
|
Args: |
||||||
|
terminal_metadata: A terminal metadata value for an operaton. |
||||||
|
code: A code value for an operation. |
||||||
|
message: A message value for an operation. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A base.Completion aggregating the given operation values. |
||||||
|
""" |
||||||
|
return _Completion(terminal_metadata, code, message) |
||||||
|
|
||||||
|
|
||||||
|
def full_subscription(operator): |
||||||
|
"""Creates a "full" base.Subscription for the given base.Operator. |
||||||
|
|
||||||
|
Args: |
||||||
|
operator: A base.Operator to be used in an operation. |
||||||
|
|
||||||
|
Returns: |
||||||
|
A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given |
||||||
|
base.Operator. |
||||||
|
""" |
||||||
|
return _Subscription(base.Subscription.Kind.FULL, None, None, operator) |
Loading…
Reference in new issue