def test_repr(self):
        p = BoltResponse(SofaHeader(a='1', b='2'), b"cdefgab", ptype=PTYPE.ONEWAY, request_id=0,
                         cmdcode=CMDCODE.HEARTBEAT,
                         respstatus=1)
        print(p)
        s = p.to_stream()
        pr = BoltResponse.from_stream(s)
        self.assertNotEqual(id(p), id(pr))
        self.assertEqual(p.header, pr.header)
        self.assertEqual(p.content, pr.content)
        self.assertEqual(p.cmdcode, pr.cmdcode)
        self.assertEqual(p.request_id, pr.request_id)
        print(pr)

        p = BoltRequest(SofaHeader(a='1', b='2'), b"jklmnhi", ptype=PTYPE.ONEWAY, request_id=0,
                        cmdcode=CMDCODE.HEARTBEAT,
                        timeout=-1)
        print(p)
        s = p.to_stream()
        pr = BoltRequest.from_stream(s)
        self.assertNotEqual(id(p), id(pr))
        self.assertEqual(p.header, pr.header)
        self.assertEqual(p.content, pr.content)
        self.assertEqual(p.cmdcode, pr.cmdcode)
        self.assertEqual(p.request_id, pr.request_id)
        print(pr)
 def test_header(self):
     h = SofaHeader(keya='key1', keyabcxcs='key2')
     b = h.to_bytes()
     self.assertEqual(len(h), len(b))
     print(b)
     h_recover = SofaHeader.from_bytes(b)
     print(h_recover)
     self.assertEqual(h, h_recover)
Beispiel #3
0
 def invoke_async(self,
                  interface,
                  method,
                  content,
                  *,
                  spanctx,
                  callback=None,
                  timeout_ms=None,
                  **headers):
     """
     call callback if callback is a callable,
     otherwise return a future
     Callback should recv a bytes object as the only argument, which is the response pkg's content
     """
     header = SofaHeader.build_header(spanctx, interface, method, **headers)
     pkg = BoltRequest.new_request(header,
                                   content,
                                   timeout_ms=timeout_ms or -1)
     fut = asyncio.run_coroutine_threadsafe(self.invoke(pkg),
                                            loop=self._loop)
     if callable(callback):
         fut.add_done_callback(
             self.callback_wrapper(
                 callback, timeout_ms / 1000 if timeout_ms else None))
         return fut
     return fut
Beispiel #4
0
    def _raw_invoke(self, interface, method_name, content, spanctx=None, target_app="", uid="",
                    timeout_ms=None, bolt_ptype=PTYPE.REQUEST, **sofa_headers_extra):

        """
        :param content:
        :param service:
        :param target_app:
        :param uid:
        :param rpc_trace_context: preserved, rpc_trace_context object, should be expanded as a dict like
                                  {'rpc_trace_context.traceId': 'xxxxx', ...}
        :param kwargs:
        """
        # FIXME spanctx might be None here
        logger.debug("Calling interface {}, spanctx: {}".format(interface, spanctx.baggage))
        header = SofaHeader.build_header(spanctx, interface, method_name, target_app=target_app, uid=uid,
                                         **sofa_headers_extra)
        p = BoltRequest.new_request(header, content, timeout_ms=timeout_ms or -1, ptype=bolt_ptype)
        for i in range(3):
            # try three times, to avoid connection failure
            try:
                conn = self._get_pool(interface).get_conn()
                conn.send(p.to_stream())
            except SocketValueError as e:
                logger.info("Call to interface {} failed, requiest_id: {}, "
                            "retried: {}, reason: {}".format(interface, p.request_id, i, e))
                continue
            except Exception as e:
                logger.error("Call to interface {} failed, requiest_id: {}, "
                             "retried: {}, reason: {}".format(interface, p.request_id, i, e))
                break
            else:
                break
        logger.debug("Called interface {}, request_id: {}".format(interface, p.request_id))
        return p.request_id, conn
Beispiel #5
0
 def _raw_invoke(self,
                 interface,
                 method_name,
                 content,
                 spanctx=None,
                 target_app="",
                 uid="",
                 timeout_ms=None,
                 bolt_ptype=PTYPE.REQUEST,
                 **sofa_headers_extra):
     """
     :param content:
     :param service:
     :param target_app:
     :param uid:
     :param rpc_trace_context: preserved, rpc_trace_context object, should be expanded as a dict like
                               {'rpc_trace_context.traceId': 'xxxxx', ...}
     :param kwargs:
     """
     header = SofaHeader.build_header(spanctx,
                                      interface,
                                      method_name,
                                      target_app=target_app,
                                      uid=uid,
                                      **sofa_headers_extra)
     p = BoltRequest.new_request(header,
                                 content,
                                 timeout_ms=timeout_ms or -1,
                                 ptype=bolt_ptype)
     conn = self._get_pool(interface).get_conn()
     conn.send(p.to_stream())
     return p.request_id, conn
Beispiel #6
0
 def invoke_oneway(self, interface, method, content, *, spanctx, **headers):
     header = SofaHeader.build_header(spanctx, interface, method, **headers)
     pkg = BoltRequest.new_request(
         header,
         content,
         timeout_ms=-1,
         codec=self._get_serialize_protocol(interface))
     asyncio.run_coroutine_threadsafe(self.invoke(pkg), loop=self._loop)
Beispiel #7
0
 def invoke_sync(self, interface, method, content, *, spanctx, timeout_ms, **headers):
     """blocking call to interface, returns responsepkg.content(as bytes)"""
     assert isinstance(timeout_ms, (int, float))
     header = SofaHeader.build_header(spanctx, interface, method, **headers)
     pkg = BoltRequest.new_request(header, content, timeout_ms=timeout_ms)
     fut = asyncio.run_coroutine_threadsafe(self.invoke(pkg), loop=self._loop)
     try:
         ret = fut.result(timeout=timeout_ms / 1000)
     except (TimeoutError, CancelledError) as e:
         logger.error("call to [{}:{}] timeout/cancelled. {}".format(interface, method, e))
         raise
     return ret.content
    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())
Beispiel #9
0
    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
Beispiel #10
0
    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