grpc python 源码分析(2):server 处理请求
版本:1.24.3
- 接受请求
首先来看 上期文章 中提到的接受请求线程 -
def _serve(state): while True: timeout = time.time() + _DEALLOCATED_SERVER_CHECK_PERIOD_S event = state.completion_queue.poll(timeout) if state.server_deallocated: _begin_shutdown_once(state) if event.completion_type != cygrpc.CompletionType.queue_timeout: if not _process_event_and_continue(state, event): return # We want to force the deletion of the previous event # ~before~ we poll again; if the event has a reference # to a shutdown Call object, this can induce spinlock. event = None
#我们要强制删除上一个事件 #〜之前〜我们再次投票; 如果事件有参考 #到关闭的Call对象,这可能导致自旋锁。
负责处理请求的是 _process_event_and_continue
函数,在之前做了一些超时的判断,决定是否处理这个请求。
下面是 _process_event_and_continue
函数的代码
def _process_event_and_continue(state, event): should_continue = True if event.tag is _SHUTDOWN_TAG: with state.lock: state.due.remove(_SHUTDOWN_TAG) if _stop_serving(state): should_continue = False elif event.tag is _REQUEST_CALL_TAG: with state.lock: state.due.remove(_REQUEST_CALL_TAG) concurrency_exceeded = ( state.maximum_concurrent_rpcs is not None and state.active_rpc_count >= state.maximum_concurrent_rpcs) rpc_state, rpc_future = _handle_call(event, state.generic_handlers, state.interceptor_pipeline, state.thread_pool, concurrency_exceeded) if rpc_state is not None: state.rpc_states.add(rpc_state) if rpc_future is not None: state.active_rpc_count += 1 rpc_future.add_done_callback( lambda unused_future: _on_call_completed(state)) if state.stage is _ServerStage.STARTED: _request_call(state) elif _stop_serving(state): should_continue = False else: rpc_state, callbacks = event.tag(event) for callback in callbacks: try: callback() except Exception: # pylint: disable=broad-except _LOGGER.exception('Exception calling callback!') if rpc_state is not None: with state.lock: state.rpc_states.remove(rpc_state) if _stop_serving(state): should_continue = False return should_continue
继续往下走
def _handle_call(rpc_event, generic_handlers, interceptor_pipeline, thread_pool, concurrency_exceeded): if not rpc_event.success: return None, None if rpc_event.call_details.method is not None: try: method_handler = _find_method_handler(rpc_event, generic_handlers, interceptor_pipeline) except Exception as exception: # pylint: disable=broad-except details = 'Exception servicing handler: {}'.format(exception) _LOGGER.exception(details) return _reject_rpc(rpc_event, cygrpc.StatusCode.unknown, b'Error in service handler!'), None if method_handler is None: return _reject_rpc(rpc_event, cygrpc.StatusCode.unimplemented, b'Method not found!'), None elif concurrency_exceeded: return _reject_rpc(rpc_event, cygrpc.StatusCode.resource_exhausted, b'Concurrent RPC limit exceeded!'), None else: return _handle_with_method_handler(rpc_event, method_handler, thread_pool) else: return None, None
这里我们主要关注 _find_method_handler
和 _handle_with_method_handler
_find_method_handler
负责获取请求对应的接口方法,例如下面这个 SayHello
方法
class Greeter(helloworld_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
其实,这就是一个字典映射,键为 接口名,值为 接口方法
def _find_method_handler(rpc_event, generic_handlers, interceptor_pipeline): def query_handlers(handler_call_details): for generic_handler in generic_handlers: method_handler = generic_handler.service(handler_call_details) if method_handler is not None: return method_handler return None handler_call_details = _HandlerCallDetails( _common.decode(rpc_event.call_details.method), rpc_event.invocation_metadata) if interceptor_pipeline is not None: return interceptor_pipeline.execute(query_handlers, handler_call_details) else: return query_handlers(handler_call_details)
# 上面代码中的 generic_handler 类型
class DictionaryGenericHandler(grpc.ServiceRpcHandler): def __init__(self, service, method_handlers): self._name = service self._method_handlers = { _common.fully_qualified_method(service, method): method_handler for method, method_handler in six.iteritems(method_handlers) } # 这是个字典推导 def service(self, handler_call_details): return self._method_handlers.get(handler_call_details.method)
继续另一个函数 _handle_with_method_handler
def _handle_with_method_handler(rpc_event, method_handler, thread_pool): state = _RPCState() with state.condition: rpc_event.call.start_server_batch( (cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),), _receive_close_on_server(state)) state.due.add(_RECEIVE_CLOSE_ON_SERVER_TOKEN) if method_handler.request_streaming: if method_handler.response_streaming: return state, _handle_stream_stream(rpc_event, state, method_handler, thread_pool) else: return state, _handle_stream_unary(rpc_event, state, method_handler, thread_pool) else: if method_handler.response_streaming: return state, _handle_unary_stream(rpc_event, state, method_handler, thread_pool) else: return state, _handle_unary_unary(rpc_event, state, method_handler, thread_pool)
这里的四个分支对应了四种rpc调用 ,详情可以看 gRPC 官方文档
我们看最简单的——请求和响应都一次性发送的 _handle_unary_unary
#请求反序列化,得到我们定义的请求对象
def _handle_unary_unary(rpc_event, state, method_handler, default_thread_pool): unary_request = _unary_request(rpc_event, state, method_handler.request_deserializer) thread_pool = _select_thread_pool_for_behavior(method_handler.unary_unary, default_thread_pool) return thread_pool.submit(_unary_response_in_pool, rpc_event, state, method_handler.unary_unary, unary_request, method_handler.request_deserializer, method_handler.response_serializer)
嗯,把任务提交给了线程池处理
继续向下挖
def _unary_response_in_pool(rpc_event, state, behavior, argument_thunk, request_deserializer, response_serializer): cygrpc.install_context_from_request_call_event(rpc_event) try: argument = argument_thunk() if argument is not None: response, proceed = _call_behavior(rpc_event, state, behavior, argument, request_deserializer) if proceed: serialized_response = _serialize_response( rpc_event, state, response, response_serializer) if serialized_response is not None: _status(rpc_event, state, serialized_response) finally: cygrpc.uninstall_context()
我们看到了 _call_behavior
函数,就是这个函数调用了我们写得接口方法 ;-)
def _call_behavior(rpc_event, state, behavior, argument, request_deserializer, send_response_callback=None): from grpc import _create_servicer_context with _create_servicer_context(rpc_event, state, request_deserializer) as context: try: response_or_iterator = None if send_response_callback is not None: response_or_iterator = behavior(argument, context, send_response_callback) else: response_or_iterator = behavior(argument, context) return response_or_iterator, True except Exception as exception: # pylint: disable=broad-except with state.condition: if state.aborted: _abort(state, rpc_event.call, cygrpc.StatusCode.unknown, b'RPC Aborted') elif exception not in state.rpc_errors: details = 'Exception calling application: {}'.format( exception) _LOGGER.exception(details) _abort(state, rpc_event.call, cygrpc.StatusCode.unknown, _common.encode(details)) return None, False
里面的 behavior
就是我们的接口方法
对于之前提及的 helloworld 例子来说,
behavior
就是下面这样(pycharm debug 得到的值)
<bound method Greeter.SayHello of <main.Greeter object at 0x0000024672710108>
还有一个工作要做,那就是发送响应,这个则是在 _unary_response_in_pool
中调用 _status
函数
def _status(rpc_event, state, serialized_response): with state.condition: if state.client is not _CANCELLED: code = _completion_code(state) details = _details(state) operations = [ cygrpc.SendStatusFromServerOperation( state.trailing_metadata, code, details, _EMPTY_FLAGS), ] if state.initial_metadata_allowed: operations.append(_get_initial_metadata_operation(state, None)) if serialized_response is not None: operations.append( cygrpc.SendMessageOperation( serialized_response, _get_send_message_op_flags_from_state(state))) rpc_event.call.start_server_batch( operations, _send_status_from_server(state, _SEND_STATUS_FROM_SERVER_TOKEN)) state.statused = True _reset_per_message_state(state) state.due.add(_SEND_STATUS_FROM_SERVER_TOKEN)
在这里,python 只是做了一点微不足道的工作,主要工作是 c++ core
负责的
-
总结
-
-
返回标记位:
-
-
def _serialize_response(rpc_event, state, response, response_serializer): serialized_response = _common.serialize(response, response_serializer) if serialized_response is None: with state.condition: _abort(state, rpc_event.call, cygrpc.StatusCode.internal, b'Failed to serialize response!') return None else: return serialized_response
-
def _send_status_from_server(state, token): def send_status_from_server(unused_send_status_from_server_event): with state.condition: return _possibly_finish_call(state, token) return send_status_from_server
非cancelled状态时候:
最后返回:
移除服务端标记
移除服务端标记
参考链接:https://www.jianshu.com/p/d78015f2aaee