mirror of https://github.com/grpc/grpc.git
Add examples for timeout, kepp_alive, reflection and health_checking (#32243)
* Add timeout example * Add pb2 file to example * Remove .proto file * Add keep_alive example * Add refelction client * fixes * Add example for health_check * Changes based on comments * Fix pylintpull/32299/head
parent
1f960697c5
commit
a190831789
17 changed files with 780 additions and 0 deletions
@ -0,0 +1,56 @@ |
||||
# Copyright 2023 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. |
||||
"""gRPC Python helloworld.Greeter client with health checking.""" |
||||
|
||||
import logging |
||||
from time import sleep |
||||
|
||||
import grpc |
||||
from grpc_health.v1 import health_pb2 |
||||
from grpc_health.v1 import health_pb2_grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
def unary_call(stub: helloworld_pb2_grpc.GreeterStub, message: str): |
||||
response = stub.SayHello(helloworld_pb2.HelloRequest(name=message), |
||||
timeout=3) |
||||
print(f"Greeter client received: {response.message}") |
||||
|
||||
|
||||
def health_check_call(stub: health_pb2_grpc.HealthStub): |
||||
request = health_pb2.HealthCheckRequest(service="helloworld.Greeter") |
||||
resp = stub.Check(request) |
||||
if resp.status == health_pb2.HealthCheckResponse.SERVING: |
||||
print("server is serving") |
||||
elif resp.status == health_pb2.HealthCheckResponse.NOT_SERVING: |
||||
print("server stopped serving") |
||||
|
||||
|
||||
def run(): |
||||
with grpc.insecure_channel('localhost:50051') as channel: |
||||
stub = helloworld_pb2_grpc.GreeterStub(channel) |
||||
health_stub = health_pb2_grpc.HealthStub(channel) |
||||
# Should succeed |
||||
unary_call(stub, 'you') |
||||
|
||||
# Check health status every 1 second for 30 seconds |
||||
for _ in range(30): |
||||
health_check_call(health_stub) |
||||
sleep(1) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
run() |
@ -0,0 +1,74 @@ |
||||
# Copyright 2023 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. |
||||
"""The Python implementation of the GRPC helloworld.Greeter server with health checking.""" |
||||
|
||||
from concurrent import futures |
||||
import logging |
||||
import threading |
||||
from time import sleep |
||||
|
||||
import grpc |
||||
from grpc_health.v1 import health |
||||
from grpc_health.v1 import health_pb2 |
||||
from grpc_health.v1 import health_pb2_grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
class Greeter(helloworld_pb2_grpc.GreeterServicer): |
||||
|
||||
def SayHello(self, request, context): |
||||
return helloworld_pb2.HelloReply(message=request.name) |
||||
|
||||
|
||||
def _toggle_health(health_servicer: health.HealthServicer, service: str): |
||||
next_status = health_pb2.HealthCheckResponse.SERVING |
||||
while True: |
||||
if next_status == health_pb2.HealthCheckResponse.SERVING: |
||||
next_status = health_pb2.HealthCheckResponse.NOT_SERVING |
||||
else: |
||||
next_status = health_pb2.HealthCheckResponse.SERVING |
||||
|
||||
health_servicer.set(service, next_status) |
||||
sleep(5) |
||||
|
||||
|
||||
def _configure_health_server(server: grpc.Server): |
||||
health_servicer = health.HealthServicer( |
||||
experimental_non_blocking=True, |
||||
experimental_thread_pool=futures.ThreadPoolExecutor(max_workers=10)) |
||||
health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server) |
||||
|
||||
# Use a daemon thread to toggle health status |
||||
toggle_health_status_thread = threading.Thread(target=_toggle_health, |
||||
args=(health_servicer, |
||||
"helloworld.Greeter"), |
||||
daemon=True) |
||||
toggle_health_status_thread.start() |
||||
|
||||
|
||||
def serve(): |
||||
port = '50051' |
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) |
||||
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) |
||||
server.add_insecure_port('[::]:' + port) |
||||
_configure_health_server(server) |
||||
server.start() |
||||
print("Server started, listening on " + port) |
||||
server.wait_for_termination() |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
serve() |
@ -0,0 +1,30 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: helloworld.proto |
||||
"""Generated protocol buffer code.""" |
||||
from google.protobuf.internal import builder as _builder |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import descriptor_pool as _descriptor_pool |
||||
from google.protobuf import symbol_database as _symbol_database |
||||
# @@protoc_insertion_point(imports) |
||||
|
||||
_sym_db = _symbol_database.Default() |
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3') |
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) |
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'helloworld_pb2', globals()) |
||||
if _descriptor._USE_C_DESCRIPTORS == False: |
||||
|
||||
DESCRIPTOR._options = None |
||||
DESCRIPTOR._serialized_options = b'\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW' |
||||
_HELLOREQUEST._serialized_start=32 |
||||
_HELLOREQUEST._serialized_end=60 |
||||
_HELLOREPLY._serialized_start=62 |
||||
_HELLOREPLY._serialized_end=91 |
||||
_GREETER._serialized_start=93 |
||||
_GREETER._serialized_end=166 |
||||
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,17 @@ |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import message as _message |
||||
from typing import ClassVar as _ClassVar, Optional as _Optional |
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor |
||||
|
||||
class HelloReply(_message.Message): |
||||
__slots__ = ["message"] |
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int] |
||||
message: str |
||||
def __init__(self, message: _Optional[str] = ...) -> None: ... |
||||
|
||||
class HelloRequest(_message.Message): |
||||
__slots__ = ["name"] |
||||
NAME_FIELD_NUMBER: _ClassVar[int] |
||||
name: str |
||||
def __init__(self, name: _Optional[str] = ...) -> None: ... |
@ -0,0 +1,70 @@ |
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! |
||||
"""Client and server classes corresponding to protobuf-defined services.""" |
||||
import grpc |
||||
|
||||
import helloworld_pb2 as helloworld__pb2 |
||||
|
||||
|
||||
class GreeterStub(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def __init__(self, channel): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
channel: A grpc.Channel. |
||||
""" |
||||
self.SayHello = channel.unary_unary( |
||||
'/helloworld.Greeter/SayHello', |
||||
request_serializer=helloworld__pb2.HelloRequest.SerializeToString, |
||||
response_deserializer=helloworld__pb2.HelloReply.FromString, |
||||
) |
||||
|
||||
|
||||
class GreeterServicer(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def SayHello(self, request, context): |
||||
"""Sends a greeting |
||||
""" |
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||
context.set_details('Method not implemented!') |
||||
raise NotImplementedError('Method not implemented!') |
||||
|
||||
|
||||
def add_GreeterServicer_to_server(servicer, server): |
||||
rpc_method_handlers = { |
||||
'SayHello': grpc.unary_unary_rpc_method_handler( |
||||
servicer.SayHello, |
||||
request_deserializer=helloworld__pb2.HelloRequest.FromString, |
||||
response_serializer=helloworld__pb2.HelloReply.SerializeToString, |
||||
), |
||||
} |
||||
generic_handler = grpc.method_handlers_generic_handler( |
||||
'helloworld.Greeter', rpc_method_handlers) |
||||
server.add_generic_rpc_handlers((generic_handler,)) |
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API. |
||||
class Greeter(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
@staticmethod |
||||
def SayHello(request, |
||||
target, |
||||
options=(), |
||||
channel_credentials=None, |
||||
call_credentials=None, |
||||
insecure=False, |
||||
compression=None, |
||||
wait_for_ready=None, |
||||
timeout=None, |
||||
metadata=None): |
||||
return grpc.experimental.unary_unary(request, target, '/helloworld.Greeter/SayHello', |
||||
helloworld__pb2.HelloRequest.SerializeToString, |
||||
helloworld__pb2.HelloReply.FromString, |
||||
options, channel_credentials, |
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata) |
@ -0,0 +1,46 @@ |
||||
# Copyright 2023 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. |
||||
"""The Python implementation of the GRPC helloworld.Greeter client with reflection.""" |
||||
|
||||
import logging |
||||
|
||||
from google.protobuf.descriptor_pool import DescriptorPool |
||||
import grpc |
||||
from grpc_reflection.v1alpha.proto_reflection_descriptor_database import \ |
||||
ProtoReflectionDescriptorDatabase |
||||
|
||||
|
||||
def run(): |
||||
print("Will try to greet world ...") |
||||
with grpc.insecure_channel('localhost:50051') as channel: |
||||
reflection_db = ProtoReflectionDescriptorDatabase(channel) |
||||
services = reflection_db.get_services() |
||||
print(f"found services: {services}") |
||||
|
||||
desc_pool = DescriptorPool(reflection_db) |
||||
service_desc = desc_pool.FindServiceByName("helloworld.Greeter") |
||||
print(f"found Greeter service with name: {service_desc.full_name}") |
||||
for methods in service_desc.methods: |
||||
print(f"found method name: {methods.full_name}") |
||||
input_type = methods.input_type |
||||
print(f"input type for this method: {input_type.full_name}") |
||||
|
||||
request_desc = desc_pool.FindMessageTypeByName( |
||||
"helloworld.HelloRequest") |
||||
print(f"found request name: {request_desc.full_name}") |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
run() |
@ -0,0 +1,67 @@ |
||||
# Copyright 2023 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. |
||||
"""gRPC Python helloworld.Greeter client with keepAlive channel options.""" |
||||
|
||||
import logging |
||||
from time import sleep |
||||
|
||||
import grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
def unary_call(stub: helloworld_pb2_grpc.GreeterStub, request_id: int, |
||||
message: str): |
||||
print("call:", request_id) |
||||
try: |
||||
response = stub.SayHello(helloworld_pb2.HelloRequest(name=message)) |
||||
print(f"Greeter client received: {response.message}") |
||||
except grpc.RpcError as rpc_error: |
||||
print('Call failed with code: ', rpc_error.code()) |
||||
|
||||
|
||||
def run(): |
||||
""" |
||||
grpc.keepalive_time_ms: The period (in milliseconds) after which a keepalive ping is |
||||
sent on the transport. |
||||
grpc.keepalive_timeout_ms: The amount of time (in milliseconds) the sender of the keepalive |
||||
ping waits for an acknowledgement. If it does not receive an acknowledgment within this |
||||
time, it will close the connection. |
||||
grpc.keepalive_permit_without_calls: If set to 1 (0 : false; 1 : true), allows keepalive |
||||
pings to be sent even if there are no calls in flight. |
||||
grpc.http2.max_pings_without_data: How many pings can the client send before needing to |
||||
send a data/header frame. |
||||
For more details, check: https://github.com/grpc/grpc/blob/master/doc/keepalive.md |
||||
""" |
||||
channel_options = [('grpc.keepalive_time_ms', 8000), |
||||
('grpc.keepalive_timeout_ms', 5000), |
||||
('grpc.http2.max_pings_without_data', 5), |
||||
('grpc.keepalive_permit_without_calls', 1)] |
||||
|
||||
with grpc.insecure_channel(target='localhost:50051', |
||||
options=channel_options) as channel: |
||||
stub = helloworld_pb2_grpc.GreeterStub(channel) |
||||
# Should succeed |
||||
unary_call(stub, 1, 'you') |
||||
|
||||
# Run 30s, run this with GRPC_VERBOSITY=DEBUG GRPC_TRACE=http_keepalive to observe logs. |
||||
# Client will be closed after receveing GOAWAY from server. |
||||
for i in range(30): |
||||
print(f"{i} seconds paased.") |
||||
sleep(1) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
run() |
@ -0,0 +1,74 @@ |
||||
# Copyright 2023 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. |
||||
"""The Python implementation of the GRPC helloworld.Greeter server with keepAlive options.""" |
||||
|
||||
from concurrent import futures |
||||
import logging |
||||
from time import sleep |
||||
|
||||
import grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
class Greeter(helloworld_pb2_grpc.GreeterServicer): |
||||
|
||||
def SayHello(self, request, context): |
||||
message = request.name |
||||
if message.startswith("[delay]"): |
||||
sleep(5) |
||||
return helloworld_pb2.HelloReply(message=message) |
||||
|
||||
|
||||
def serve(): |
||||
""" |
||||
grpc.keepalive_time_ms: The period (in milliseconds) after which a keepalive ping is |
||||
sent on the transport. |
||||
grpc.keepalive_timeout_ms: The amount of time (in milliseconds) the sender of the keepalive |
||||
ping waits for an acknowledgement. If it does not receive an acknowledgment within |
||||
this time, it will close the connection. |
||||
grpc.http2.min_ping_interval_without_data_ms: Minimum allowed time (in milliseconds) |
||||
between a server receiving successive ping frames without sending any data/header frame. |
||||
grpc.max_connection_idle_ms: Maximum time (in milliseconds) that a channel may have no |
||||
outstanding rpcs, after which the server will close the connection. |
||||
grpc.max_connection_age_ms: Maximum time (in milliseconds) that a channel may exist. |
||||
grpc.max_connection_age_grace_ms: Grace period (in milliseconds) after the channel |
||||
reaches its max age. |
||||
grpc.http2.max_pings_without_data: How many pings can the client send before needing to |
||||
send a data/header frame. |
||||
grpc.keepalive_permit_without_calls: If set to 1 (0 : false; 1 : true), allows keepalive |
||||
pings to be sent even if there are no calls in flight. |
||||
For more details, check: https://github.com/grpc/grpc/blob/master/doc/keepalive.md |
||||
""" |
||||
server_options = [('grpc.keepalive_time_ms', 20000), |
||||
('grpc.keepalive_timeout_ms', 10000), |
||||
('grpc.http2.min_ping_interval_without_data_ms', 5000), |
||||
('grpc.max_connection_idle_ms', 10000), |
||||
('grpc.max_connection_age_ms', 30000), |
||||
('grpc.max_connection_age_grace_ms', 5000), |
||||
('grpc.http2.max_pings_without_data', 5), |
||||
('grpc.keepalive_permit_without_calls', 1)] |
||||
port = '50051' |
||||
server = grpc.server(thread_pool=futures.ThreadPoolExecutor(max_workers=10), |
||||
options=server_options) |
||||
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) |
||||
server.add_insecure_port('[::]:' + port) |
||||
server.start() |
||||
print("Server started, listening on " + port) |
||||
server.wait_for_termination() |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
serve() |
@ -0,0 +1,30 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: helloworld.proto |
||||
"""Generated protocol buffer code.""" |
||||
from google.protobuf.internal import builder as _builder |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import descriptor_pool as _descriptor_pool |
||||
from google.protobuf import symbol_database as _symbol_database |
||||
# @@protoc_insertion_point(imports) |
||||
|
||||
_sym_db = _symbol_database.Default() |
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3') |
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) |
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'helloworld_pb2', globals()) |
||||
if _descriptor._USE_C_DESCRIPTORS == False: |
||||
|
||||
DESCRIPTOR._options = None |
||||
DESCRIPTOR._serialized_options = b'\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW' |
||||
_HELLOREQUEST._serialized_start=32 |
||||
_HELLOREQUEST._serialized_end=60 |
||||
_HELLOREPLY._serialized_start=62 |
||||
_HELLOREPLY._serialized_end=91 |
||||
_GREETER._serialized_start=93 |
||||
_GREETER._serialized_end=166 |
||||
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,17 @@ |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import message as _message |
||||
from typing import ClassVar as _ClassVar, Optional as _Optional |
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor |
||||
|
||||
class HelloReply(_message.Message): |
||||
__slots__ = ["message"] |
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int] |
||||
message: str |
||||
def __init__(self, message: _Optional[str] = ...) -> None: ... |
||||
|
||||
class HelloRequest(_message.Message): |
||||
__slots__ = ["name"] |
||||
NAME_FIELD_NUMBER: _ClassVar[int] |
||||
name: str |
||||
def __init__(self, name: _Optional[str] = ...) -> None: ... |
@ -0,0 +1,70 @@ |
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! |
||||
"""Client and server classes corresponding to protobuf-defined services.""" |
||||
import grpc |
||||
|
||||
import helloworld_pb2 as helloworld__pb2 |
||||
|
||||
|
||||
class GreeterStub(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def __init__(self, channel): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
channel: A grpc.Channel. |
||||
""" |
||||
self.SayHello = channel.unary_unary( |
||||
'/helloworld.Greeter/SayHello', |
||||
request_serializer=helloworld__pb2.HelloRequest.SerializeToString, |
||||
response_deserializer=helloworld__pb2.HelloReply.FromString, |
||||
) |
||||
|
||||
|
||||
class GreeterServicer(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def SayHello(self, request, context): |
||||
"""Sends a greeting |
||||
""" |
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||
context.set_details('Method not implemented!') |
||||
raise NotImplementedError('Method not implemented!') |
||||
|
||||
|
||||
def add_GreeterServicer_to_server(servicer, server): |
||||
rpc_method_handlers = { |
||||
'SayHello': grpc.unary_unary_rpc_method_handler( |
||||
servicer.SayHello, |
||||
request_deserializer=helloworld__pb2.HelloRequest.FromString, |
||||
response_serializer=helloworld__pb2.HelloReply.SerializeToString, |
||||
), |
||||
} |
||||
generic_handler = grpc.method_handlers_generic_handler( |
||||
'helloworld.Greeter', rpc_method_handlers) |
||||
server.add_generic_rpc_handlers((generic_handler,)) |
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API. |
||||
class Greeter(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
@staticmethod |
||||
def SayHello(request, |
||||
target, |
||||
options=(), |
||||
channel_credentials=None, |
||||
call_credentials=None, |
||||
insecure=False, |
||||
compression=None, |
||||
wait_for_ready=None, |
||||
timeout=None, |
||||
metadata=None): |
||||
return grpc.experimental.unary_unary(request, target, '/helloworld.Greeter/SayHello', |
||||
helloworld__pb2.HelloRequest.SerializeToString, |
||||
helloworld__pb2.HelloReply.FromString, |
||||
options, channel_credentials, |
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata) |
@ -0,0 +1,45 @@ |
||||
# Copyright 2023 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. |
||||
"""gRPC Python helloworld.Greeter client with call timeout parameters.""" |
||||
|
||||
import logging |
||||
|
||||
import grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
def unary_call(stub: helloworld_pb2_grpc.GreeterStub, request_id: int, |
||||
message: str): |
||||
print("call:", request_id) |
||||
try: |
||||
response = stub.SayHello(helloworld_pb2.HelloRequest(name=message), |
||||
timeout=3) |
||||
print(f"Greeter client received: {response.message}") |
||||
except grpc.RpcError as rpc_error: |
||||
print(f"Call failed with code: {rpc_error.code()}") |
||||
|
||||
|
||||
def run(): |
||||
with grpc.insecure_channel('localhost:50051') as channel: |
||||
stub = helloworld_pb2_grpc.GreeterStub(channel) |
||||
# Should success |
||||
unary_call(stub, 1, 'you') |
||||
# Should fail with DEADLINE_EXCEEDED |
||||
unary_call(stub, 2, '[delay] you') |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
run() |
@ -0,0 +1,46 @@ |
||||
# Copyright 2023 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. |
||||
"""The Python implementation of the GRPC helloworld.Greeter server.""" |
||||
|
||||
from concurrent import futures |
||||
import logging |
||||
from time import sleep |
||||
|
||||
import grpc |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
class Greeter(helloworld_pb2_grpc.GreeterServicer): |
||||
|
||||
def SayHello(self, request, context): |
||||
message = request.name |
||||
if message.startswith("[delay]"): |
||||
sleep(5) |
||||
return helloworld_pb2.HelloReply(message=message) |
||||
|
||||
|
||||
def serve(): |
||||
port = '50051' |
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) |
||||
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) |
||||
server.add_insecure_port('[::]:' + port) |
||||
server.start() |
||||
print("Server started, listening on " + port) |
||||
server.wait_for_termination() |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
serve() |
@ -0,0 +1,30 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: helloworld.proto |
||||
"""Generated protocol buffer code.""" |
||||
from google.protobuf.internal import builder as _builder |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import descriptor_pool as _descriptor_pool |
||||
from google.protobuf import symbol_database as _symbol_database |
||||
# @@protoc_insertion_point(imports) |
||||
|
||||
_sym_db = _symbol_database.Default() |
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3') |
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) |
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'helloworld_pb2', globals()) |
||||
if _descriptor._USE_C_DESCRIPTORS == False: |
||||
|
||||
DESCRIPTOR._options = None |
||||
DESCRIPTOR._serialized_options = b'\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW' |
||||
_HELLOREQUEST._serialized_start=32 |
||||
_HELLOREQUEST._serialized_end=60 |
||||
_HELLOREPLY._serialized_start=62 |
||||
_HELLOREPLY._serialized_end=91 |
||||
_GREETER._serialized_start=93 |
||||
_GREETER._serialized_end=166 |
||||
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,17 @@ |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import message as _message |
||||
from typing import ClassVar as _ClassVar, Optional as _Optional |
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor |
||||
|
||||
class HelloReply(_message.Message): |
||||
__slots__ = ["message"] |
||||
MESSAGE_FIELD_NUMBER: _ClassVar[int] |
||||
message: str |
||||
def __init__(self, message: _Optional[str] = ...) -> None: ... |
||||
|
||||
class HelloRequest(_message.Message): |
||||
__slots__ = ["name"] |
||||
NAME_FIELD_NUMBER: _ClassVar[int] |
||||
name: str |
||||
def __init__(self, name: _Optional[str] = ...) -> None: ... |
@ -0,0 +1,70 @@ |
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! |
||||
"""Client and server classes corresponding to protobuf-defined services.""" |
||||
import grpc |
||||
|
||||
import helloworld_pb2 as helloworld__pb2 |
||||
|
||||
|
||||
class GreeterStub(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def __init__(self, channel): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
channel: A grpc.Channel. |
||||
""" |
||||
self.SayHello = channel.unary_unary( |
||||
'/helloworld.Greeter/SayHello', |
||||
request_serializer=helloworld__pb2.HelloRequest.SerializeToString, |
||||
response_deserializer=helloworld__pb2.HelloReply.FromString, |
||||
) |
||||
|
||||
|
||||
class GreeterServicer(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def SayHello(self, request, context): |
||||
"""Sends a greeting |
||||
""" |
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||
context.set_details('Method not implemented!') |
||||
raise NotImplementedError('Method not implemented!') |
||||
|
||||
|
||||
def add_GreeterServicer_to_server(servicer, server): |
||||
rpc_method_handlers = { |
||||
'SayHello': grpc.unary_unary_rpc_method_handler( |
||||
servicer.SayHello, |
||||
request_deserializer=helloworld__pb2.HelloRequest.FromString, |
||||
response_serializer=helloworld__pb2.HelloReply.SerializeToString, |
||||
), |
||||
} |
||||
generic_handler = grpc.method_handlers_generic_handler( |
||||
'helloworld.Greeter', rpc_method_handlers) |
||||
server.add_generic_rpc_handlers((generic_handler,)) |
||||
|
||||
|
||||
# This class is part of an EXPERIMENTAL API. |
||||
class Greeter(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
@staticmethod |
||||
def SayHello(request, |
||||
target, |
||||
options=(), |
||||
channel_credentials=None, |
||||
call_credentials=None, |
||||
insecure=False, |
||||
compression=None, |
||||
wait_for_ready=None, |
||||
timeout=None, |
||||
metadata=None): |
||||
return grpc.experimental.unary_unary(request, target, '/helloworld.Greeter/SayHello', |
||||
helloworld__pb2.HelloRequest.SerializeToString, |
||||
helloworld__pb2.HelloReply.FromString, |
||||
options, channel_credentials, |
||||
insecure, call_credentials, compression, wait_for_ready, timeout, metadata) |
Loading…
Reference in new issue