def handle(self): try: fixed_header_bs = self._readexactly(BoltRequest.bolt_header_size()) header = BoltRequest.bolt_header_from_stream(fixed_header_bs) call_type = header['ptype'] cmdcode = header['cmdcode'] class_name = self._readexactly(header['class_len']) bs = self._readexactly(header['header_len']) sofa_header = SofaHeader.from_bytes(bs) body = self._readexactly(header['content_len']) if self.server.ready: self.server.ready.set() request_id = header['request_id'] if cmdcode == CMDCODE.HEARTBEAT: self.wfile.write(HeartbeatResponse.response_to(request_id).to_stream()) self.wfile.flush() return if cmdcode == CMDCODE.RESPONSE: raise ClientError("wrong cmdcode:[{}]".format(cmdcode)) if class_name != "com.alipay.sofa.rpc.core.request.SofaRequest".encode(): raise ClientError("wrong class_name:[{}]".format(class_name)) service = sofa_header.get('sofa_head_target_service') or sofa_header.get('service') if not service: self.wfile.write(FailResponse.response_to(request_id, RESPSTATUS.CLIENT_SEND_ERROR).to_stream()) self.wfile.flush() logger.error("Missing service name in sofa header [{}]".format(sofa_header)) return method = sofa_header.get('sofa_head_method_name') if not method: self.wfile.write(FailResponse.response_to(request_id, RESPSTATUS.CLIENT_SEND_ERROR).to_stream()) self.wfile.flush() logger.error("Missing method name in sofa header [{}]".format(sofa_header)) return spanctx = tracer.extract(opentracing.Format.TEXT_MAP, sofa_header) ret = self.handle_request(spanctx, service, method, body) self.wfile.write(ret) self.wfile.flush() except OSError as e: if e.errno != ECONNRESET: raise except Exception as e: logger.error(traceback.format_exc())
async def _handler_connection(self, reader, writer): """ Full duplex model Only recv request here, run a new coro to process and send back response in same connection. """ logger.info("connection created.") first_req = True while True: try: try: fixed_header_bs = await reader.readexactly( BoltRequest.bolt_header_size()) except asyncio.IncompleteReadError: if first_req: # just connected, do nothing. most likely L4 health checks from mosn/upstream await self._close_writer(writer) break # break the loop raise first_req = False logger.debug( "received bolt header({})".format(fixed_header_bs)) header = BoltRequest.bolt_header_from_stream(fixed_header_bs) call_type = header['ptype'] cmdcode = header['cmdcode'] class_name = await reader.readexactly(header['class_len']) logger.debug("received classname({})".format(class_name)) bs = await reader.readexactly(header['header_len']) logger.debug("received sofa header({})".format(bs)) sofa_header = SofaHeader.from_bytes(bs) body = await reader.readexactly(header['content_len']) logger.debug("received sofa body({})".format(body)) if cmdcode == CMDCODE.HEARTBEAT: logger.info("received heartbeat, request_id={}".format( header['request_id'])) asyncio.ensure_future( self._write_msg( writer, HeartbeatResponse.response_to( header['request_id']).to_stream())) continue if cmdcode == CMDCODE.RESPONSE: raise ClientError("wrong cmdcode:[{}]".format(cmdcode)) if class_name != "com.alipay.sofa.rpc.core.request.SofaRequest".encode( ): raise ClientError( "wrong class_name:[{}]".format(class_name)) logger.debug("dispatching request[{}]".format( header['request_id'])) asyncio.ensure_future( self._dispatch(call_type, header['request_id'], sofa_header, body, timeout_ms=header['timeout'], codec=header['codec'], writer=writer)) except ClientError as e: logger.error(str(e) + " returning CLIENT_SEND_ERROR") await self._write_msg( writer, FailResponse.response_to( header['request_id'], RESPSTATUS.CLIENT_SEND_ERROR).to_stream()) continue except ProtocolError as e: logger.error(str(e) + " returning CODEC_EXCEPTION") await self._write_msg( writer, FailResponse.response_to( header['request_id'], RESPSTATUS.CODEC_EXCEPTION).to_stream()) continue except EOFError as e: logger.warning("Connection closed by remote: {}".format(e)) try: await writer.drain( ) # clean the buffer, avoid backpressure writer.write( FailResponse.response_to( header['request_id'], RESPSTATUS.CONNECTION_CLOSED).to_stream()) except: pass await self._close_writer(writer) break except Exception: logger.error("Unknow exception, close connection") logger.error(traceback.format_exc()) try: await writer.drain( ) # clean the buffer, avoid backpressure writer.write( FailResponse.response_to( header['request_id'], RESPSTATUS.UNKNOWN).to_stream()) except: pass await self._close_writer(writer) break
async def _dispatch(self, call_type, request_id, sofa_header, body, *, timeout_ms, codec, writer): """send request to handler""" service = sofa_header.get( 'sofa_head_target_service') or sofa_header.get('service') if not service: await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.CLIENT_SEND_ERROR, codec=codec).to_stream(), ) logger.error( "Missing service name in sofa header [{}]".format(sofa_header)) return method = sofa_header.get('sofa_head_method_name') if not method: await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.CLIENT_SEND_ERROR, codec=codec).to_stream()) logger.error( "Missing method name in sofa header [{}]".format(sofa_header)) return spanctx = tracer.extract(opentracing.Format.TEXT_MAP, sofa_header) try: future = self.handler.handle_request(spanctx, service, method, body) except NoProcessorError: await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.NO_PROCESSOR, codec=codec).to_stream(), ) return except Exception: await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.SERVER_EXCEPTION, codec=codec).to_stream(), ) return if PTYPE.ONEWAY == call_type: # Just return future return future try: afut = asyncio.wrap_future(future) result = await asyncio.wait_for( afut, timeout_ms / 1000 if timeout_ms > 0 else None) except (asyncio.CancelledError, asyncio.TimeoutError) as e: logger.error( "Task run cancelled/timeout in {}ms, service:[{}]: error:[{}]". format(timeout_ms, service, e)) await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.TIMEOUT, codec=codec).to_stream(), ) return except Exception: logger.error(traceback.format_exc()) await self._write_msg( writer, FailResponse.response_to(request_id, RESPSTATUS.UNKNOWN, codec=codec).to_stream(), ) return if result: header = dict() tracer.inject(spanctx, opentracing.Format.TEXT_MAP, header) pkg = BoltResponse.response_to(result, request_id=request_id, codec=codec) try: await self._write_msg(writer, pkg.to_stream()) except Exception: logger.error(traceback.format_exc())
def _handler_connection(self, reader, writer): """ Full duplex model Only recv request here, run a new coro to process and send back response in same connection. """ first_req = True while True: try: try: fixed_header_bs = yield from reader.readexactly( BoltRequest.bolt_header_size()) except asyncio.streams.IncompleteReadError: if first_req: raise first_req = False header = BoltRequest.bolt_header_from_stream(fixed_header_bs) call_type = header['ptype'] cmdcode = header['cmdcode'] class_name = yield from reader.readexactly(header['class_len']) bs = yield from reader.readexactly(header['header_len']) sofa_header = SofaHeader.from_bytes(bs) body = yield from reader.readexactly(header['content_len']) if cmdcode == CMDCODE.HEARTBEAT: asyncio.ensure_future( self._write_msg( writer, HeartbeatResponse.response_to( header['request_id']).to_stream())) continue if cmdcode == CMDCODE.RESPONSE: raise ClientError("wrong cmdcode:[{}]".format(cmdcode)) if class_name != "com.alipay.sofa.rpc.core.request.SofaRequest".encode( ): raise ClientError( "wrong class_name:[{}]".format(class_name)) asyncio.ensure_future( self._dispatch(call_type, header['request_id'], sofa_header, body, timeout_ms=header['timeout'], writer=writer)) except ClientError as e: logger.error(str(e)) yield from self._write_msg( writer, FailResponse.response_to( header['request_id'], RESPSTATUS.CLIENT_SEND_ERROR).to_stream()) continue except ProtocolError as e: logger.error(str(e)) yield from self._write_msg( writer, FailResponse.response_to( header['request_id'], RESPSTATUS.CODEC_EXCEPTION).to_stream()) continue except EOFError as e: logger.info("Connection closed: {}".format(e)) try: yield from writer.drain( ) # clean the buffer, avoid backpressure writer.write( FailResponse.response_to( header['request_id'], RESPSTATUS.CONNECTION_CLOSED).to_stream()) except: pass try: writer.write_eof() yield from writer.drain() except: pass writer.close() break except Exception: logger.error(traceback.format_exc()) try: yield from writer.drain( ) # clean the buffer, avoid backpressure writer.write( FailResponse.response_to( header['request_id'], RESPSTATUS.UNKNOWN).to_stream()) except: pass try: writer.write_eof() yield from writer.drain() except: pass writer.close() break