def handle_result(self, response_stream, worker_ctx, result, exc_info): if self.cardinality in (Cardinality.STREAM_UNARY, Cardinality.UNARY_UNARY): result = (result, ) if exc_info is None: try: response_stream.populate(result) except Exception as exception: error = GrpcError( status=StatusCode.UNKNOWN, details="Exception iterating responses: {}".format( exception), debug_error_string="<traceback>", ) response_stream.close(error) else: error = GrpcError( status=StatusCode.UNKNOWN, details="Exception calling application: {}".format( exc_info[1]), debug_error_string="<traceback>", ) response_stream.close(error) return result, exc_info
def handle_request(self, request_stream, response_stream): try: method_path = request_stream.headers.get(":path") entrypoint = self.entrypoints[method_path] except KeyError: raise GrpcError( status=StatusCode.UNIMPLEMENTED, details="Method not found!", debug_error_string="<traceback>", ) encoding = request_stream.headers.get("grpc-encoding", "identity") if encoding not in SUPPORTED_ENCODINGS: raise GrpcError( status=StatusCode.UNIMPLEMENTED, details="Algorithm not supported: {}".format(encoding), debug_error_string="<traceback>", ) timeout = request_stream.headers.get("grpc-timeout") if timeout: timeout = unbucket_timeout(timeout) self.container.spawn_managed_thread( partial(self.timeout, request_stream, response_stream, timeout)) self.container.spawn_managed_thread( partial(entrypoint.handle_request, request_stream, response_stream))
def test_close_with_error(self): stream = StreamBase(1) error = GrpcError("boom", "details", "error string") stream.close(error) assert stream.closed assert stream.queue.get() == error
def handle_request(self, request_stream, response_stream): request = request_stream.consume(self.input_type) if self.cardinality in (Cardinality.UNARY_STREAM, Cardinality.UNARY_UNARY): request = next(request) context = GrpcContext(request_stream, response_stream) args = (request, context) kwargs = {} context_data = context_data_from_metadata( context.invocation_metadata()) handle_result = partial(self.handle_result, response_stream) try: self.container.spawn_worker( self, args, kwargs, context_data=context_data, handle_result=handle_result, ) except ContainerBeingKilled: raise GrpcError( status=StatusCode.UNAVAILABLE, details="Server shutting down", debug_error_string="<traceback>", )
def test_error_on_queue(self, generate_messages): stream = SendStream(1) stream.populate(generate_messages(count=2, length=20)) error = GrpcError("boom", "details", "error string") stream.close(error) with pytest.raises(GrpcError): stream.flush_queue_to_buffer()
def test_consume_grpc_error(self): stream = ReceiveStream(1) error = GrpcError("boom", "details", "message") stream.queue.put(error) message_type = Mock() with pytest.raises(GrpcError): next(stream.consume(message_type))
def send_stream(self, result): try: for item in result: self.send(item) except grpc.RpcError as exc: state = exc._state error = GrpcError(state.code, state.details, state.debug_error_string) self.send(error) self.send(self.ENDSTREAM, close=True)
def test_stream_closed_with_error(self): stream = SendStream(1) error = GrpcError("boom", "details", "error string") stream.close(error) max_bytes = 10 chunk_size = 5 with pytest.raises(GrpcError): next(stream.read(max_bytes, chunk_size))
def timeout(self, send_stream, response_stream, deadline): start = time.time() while True: elapsed = time.time() - start if elapsed > deadline: error = GrpcError( status=StatusCode.DEADLINE_EXCEEDED, details="Deadline Exceeded", debug_error_string="<traceback>", ) response_stream.close(error) send_stream.close() time.sleep(0.001)
def send_data(self, stream_id): try: super().send_data(stream_id) except UnsupportedEncoding: response_stream = self.receive_streams[stream_id] request_stream = self.send_streams[stream_id] error = GrpcError( status=StatusCode.UNIMPLEMENTED, details="Algorithm not supported: {}".format(request_stream.encoding), debug_error_string="<traceback>", ) response_stream.close(error) request_stream.close()
def timeout(self, request_stream, response_stream, deadline): start = time.time() while True: elapsed = time.time() - start if elapsed > deadline: request_stream.close() # XXX does server actually need to do this according to the spec? # perhaps we could just close the stream. error = GrpcError( status=StatusCode.DEADLINE_EXCEEDED, details="Deadline Exceeded", debug_error_string="<traceback>", ) response_stream.close(error) break time.sleep(0.001)
def trailers_received(self, event): """ Called when trailers are received on a stream. If the trailers contain an error, we should raise it here. """ super().trailers_received(event) stream_id = event.stream_id response_stream = self.receive_streams.get(stream_id) if response_stream is None: self.conn.reset_stream(stream_id, error_code=ErrorCodes.PROTOCOL_ERROR) return trailers = response_stream.trailers if int(trailers.get("grpc-status", 0)) > 0: error = GrpcError.from_headers(trailers) response_stream.close(error)
def execute(command, stub): method = getattr(stub, command.method_name) request = command.get_request() compression = command.kwargs.pop("compression", None) if compression: command.kwargs["metadata"] = list(command.kwargs.get( "metadata", [])) + [("grpc-internal-encoding-request", compression) ] response_metadata = {} try: if command.cardinality in (Cardinality.STREAM_UNARY, Cardinality.UNARY_UNARY): response_future = method.future(request, **command.kwargs) response_metadata["code"] = response_future.code() response_metadata["details"] = response_future.details() response_metadata["initial_metadata"] = list( map(tuple, response_future.initial_metadata())) response_metadata["trailing_metadata"] = list( map(tuple, response_future.trailing_metadata())) response = response_future.result() else: # .future() interface for RPCs with STREAM responses not supported response = method(request, **command.kwargs) except grpc.RpcError as exc: state = exc._state response_metadata["code"] = state.code response_metadata["details"] = state.details response = GrpcError(state.code, state.details, state.debug_error_string) command.send_response(response) command.send_metadata(response_metadata)