mirror of https://github.com/grpc/grpc.git
* Refactors how Task wrapper work on the client-side * Refactors final status propagation and unify similar classes * Adds unary-stream API for both-sides * Refactors each abstraction layer multicallable / call / channel * Revisits the design of cancellation on client-side * Makes server methods interuptable * Fixes a zombie coroutine issue in shutdown pathpull/21232/head
parent
f5666958f9
commit
5e5781c961
28 changed files with 1727 additions and 751 deletions
@ -0,0 +1,127 @@ |
||||
# Copyright 2019 The gRPC Authors |
||||
# |
||||
# 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. |
||||
"""Abstract base classes for client-side Call objects. |
||||
|
||||
Call objects represents the RPC itself, and offer methods to access / modify |
||||
its information. They also offer methods to manipulate the life-cycle of the |
||||
RPC, e.g. cancellation. |
||||
""" |
||||
|
||||
from abc import ABCMeta, abstractmethod |
||||
from typing import AsyncIterable, Awaitable, Generic, Text |
||||
|
||||
import grpc |
||||
|
||||
from ._typing import MetadataType, RequestType, ResponseType |
||||
|
||||
__all__ = 'Call', 'UnaryUnaryCall', 'UnaryStreamCall' |
||||
|
||||
|
||||
class Call(grpc.RpcContext, metaclass=ABCMeta): |
||||
"""The abstract base class of an RPC on the client-side.""" |
||||
|
||||
@abstractmethod |
||||
def cancelled(self) -> bool: |
||||
"""Return True if the RPC is cancelled. |
||||
|
||||
The RPC is cancelled when the cancellation was requested with cancel(). |
||||
|
||||
Returns: |
||||
A bool indicates whether the RPC is cancelled or not. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
def done(self) -> bool: |
||||
"""Return True if the RPC is done. |
||||
|
||||
An RPC is done if the RPC is completed, cancelled or aborted. |
||||
|
||||
Returns: |
||||
A bool indicates if the RPC is done. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def initial_metadata(self) -> MetadataType: |
||||
"""Accesses the initial metadata sent by the server. |
||||
|
||||
Coroutine continues once the value is available. |
||||
|
||||
Returns: |
||||
The initial :term:`metadata`. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def trailing_metadata(self) -> MetadataType: |
||||
"""Accesses the trailing metadata sent by the server. |
||||
|
||||
Coroutine continues once the value is available. |
||||
|
||||
Returns: |
||||
The trailing :term:`metadata`. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def code(self) -> grpc.StatusCode: |
||||
"""Accesses the status code sent by the server. |
||||
|
||||
Coroutine continues once the value is available. |
||||
|
||||
Returns: |
||||
The StatusCode value for the RPC. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def details(self) -> Text: |
||||
"""Accesses the details sent by the server. |
||||
|
||||
Coroutine continues once the value is available. |
||||
|
||||
Returns: |
||||
The details string of the RPC. |
||||
""" |
||||
|
||||
|
||||
class UnaryUnaryCall(Generic[RequestType, ResponseType], Call, metaclass=ABCMeta): |
||||
"""The abstract base class of an unary-unary RPC on the client-side.""" |
||||
|
||||
@abstractmethod |
||||
def __await__(self) -> Awaitable[ResponseType]: |
||||
"""Await the response message to be ready. |
||||
|
||||
Returns: |
||||
The response message of the RPC. |
||||
""" |
||||
|
||||
|
||||
class UnaryStreamCall(Generic[RequestType, ResponseType], Call, metaclass=ABCMeta): |
||||
|
||||
@abstractmethod |
||||
def __aiter__(self) -> AsyncIterable[ResponseType]: |
||||
"""Returns the async iterable representation that yields messages. |
||||
|
||||
Under the hood, it is calling the "read" method. |
||||
|
||||
Returns: |
||||
An async iterable object that yields messages. |
||||
""" |
||||
|
||||
@abstractmethod |
||||
async def read(self) -> ResponseType: |
||||
"""Reads one message from the RPC. |
||||
|
||||
Parallel read operations is not allowed. |
||||
|
||||
Returns: |
||||
A response message of the RPC. |
||||
""" |
@ -0,0 +1,32 @@ |
||||
# Copyright 2019 The gRPC Authors |
||||
# |
||||
# 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. |
||||
|
||||
package( |
||||
default_testonly = 1, |
||||
default_visibility = ["//visibility:public"], |
||||
) |
||||
|
||||
py_binary( |
||||
name = "server", |
||||
srcs = ["server.py"], |
||||
python_version = "PY3", |
||||
deps = [ |
||||
"//external:six", |
||||
"//src/proto/grpc/testing:benchmark_service_py_pb2", |
||||
"//src/proto/grpc/testing:benchmark_service_py_pb2_grpc", |
||||
"//src/proto/grpc/testing:py_messages_proto", |
||||
"//src/python/grpcio/grpc:grpcio", |
||||
"//src/python/grpcio_tests/tests/unit/framework/common", |
||||
], |
||||
) |
@ -0,0 +1,45 @@ |
||||
# Copyright 2019 The gRPC Authors |
||||
# |
||||
# 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. |
||||
"""Tests AioRpcError class.""" |
||||
|
||||
import logging |
||||
import unittest |
||||
|
||||
import grpc |
||||
|
||||
from grpc.experimental.aio._call import AioRpcError |
||||
from tests_aio.unit._test_base import AioTestBase |
||||
|
||||
|
||||
class TestAioRpcError(unittest.TestCase): |
||||
_TEST_INITIAL_METADATA = ("initial metadata",) |
||||
_TEST_TRAILING_METADATA = ("trailing metadata",) |
||||
|
||||
def test_attributes(self): |
||||
aio_rpc_error = AioRpcError( |
||||
grpc.StatusCode.CANCELLED, |
||||
"details", |
||||
initial_metadata=self._TEST_INITIAL_METADATA, |
||||
trailing_metadata=self._TEST_TRAILING_METADATA) |
||||
self.assertEqual(aio_rpc_error.code(), grpc.StatusCode.CANCELLED) |
||||
self.assertEqual(aio_rpc_error.details(), "details") |
||||
self.assertEqual(aio_rpc_error.initial_metadata(), |
||||
self._TEST_INITIAL_METADATA) |
||||
self.assertEqual(aio_rpc_error.trailing_metadata(), |
||||
self._TEST_TRAILING_METADATA) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
unittest.main(verbosity=2) |
Loading…
Reference in new issue