def handle(request): # kwargs for this function's response_cls constructor response_kwargs = {} status = OK try: response = yield gen.maybe_future(handler(request)) except Exception as e: response = Response() for exc_spec in response_spec.exception_specs: # Each exc_spec is a thriftrw.spec.FieldSpec. The spec # attribute on that is the TypeSpec for the Exception class # and the surface on the TypeSpec is the exception class. exc_cls = exc_spec.spec.surface if isinstance(e, exc_cls): status = FAILED response_kwargs[exc_spec.name] = e break else: raise_exc_info(sys.exc_info()) else: response = response_from_mixed(response) if response_spec.return_spec is not None: assert response.body is not None, ( 'Expected a value to be returned for %s, ' 'but recieved None - only void procedures can ' 'return None.' % function.endpoint) response_kwargs['success'] = response.body response.status = status response.body = response_cls(**response_kwargs) raise gen.Return(response)
def handle(request): # kwargs for this function's response_cls constructor response_kwargs = {} status = OK try: response = yield gen.maybe_future(handler(request)) except Exception as e: response = Response() for exc_spec in response_spec.exception_specs: # Each exc_spec is a thriftrw.spec.FieldSpec. The spec # attribute on that is the TypeSpec for the Exception class # and the surface on the TypeSpec is the exception class. exc_cls = exc_spec.spec.surface if isinstance(e, exc_cls): status = FAILED response_kwargs[exc_spec.name] = e break else: raise_exc_info(sys.exc_info()) else: response = response_from_mixed(response) if response_spec.return_spec is not None: assert response.body is not None, ( 'Expected a value to be returned for %s, ' 'but recieved None - only void procedures can ' 'return None.' % function.endpoint ) response_kwargs['success'] = response.body response.status = status response.body = response_cls(**response_kwargs) raise gen.Return(response)
def handler(request): result = ThriftResponse(result_type()) response = Response() try: response = yield gen.maybe_future(f(request)) except Exception: result.write_exc_info(sys.exc_info()) else: response = response_from_mixed(response) result.write_result(response.body) response.status = result.code response.body = result.result raise gen.Return(response)
def handle_call(self, request, connection): # read arg_1 so that handle_call is able to get the endpoint # name and find the endpoint handler. # the arg_1 value will be store in the request.endpoint field. # NOTE: after here, the correct way to access value of arg_1 is through # request.endpoint. The original argstream[0] is no longer valid. If # user still tries read from it, it will return empty. chunk = yield request.argstreams[0].read() response = None while chunk: request.endpoint += chunk chunk = yield request.argstreams[0].read() log.debug('Received a call to %s.', request.endpoint) tchannel = connection.tchannel # event: receive_request request.tracing.name = request.endpoint tchannel.event_emitter.fire(EventType.before_receive_request, request) handler = self.handlers.get(request.endpoint) if handler is None: handler = self.handlers[self.FALLBACK] requested_as = request.headers.get('as', None) expected_as = handler.req_serializer.name if request.endpoint in self.handlers and requested_as != expected_as: connection.send_error( BadRequestError( description=("Server expected a '%s' but request is '%s'" % ( expected_as, requested_as, )), id=request.id, tracing=request.tracing, )) raise gen.Return(None) request.serializer = handler.req_serializer response = DeprecatedResponse( id=request.id, checksum=request.checksum, tracing=request.tracing, connection=connection, headers={'as': request.headers.get('as', 'raw')}, serializer=handler.resp_serializer, ) connection.post_response(response) try: # New impl - the handler takes a request and returns a response if self._handler_returns_response: # convert deprecated req to new top-level req b = yield request.get_body() he = yield request.get_header() t = TransportHeaders.from_dict(request.headers) new_req = Request( body=b, headers=he, transport=t, endpoint=request.endpoint, service=request.service, timeout=request.ttl, ) # Not safe to have coroutine yields statement within # stack context. # The right way to do it is: # with request_context(..): # future = f() # yield future with request_context(request.tracing): f = handler.endpoint(new_req) new_resp = yield gen.maybe_future(f) # instantiate a tchannel.Response new_resp = response_from_mixed(new_resp) response.code = new_resp.status # assign resp values to dep response response.write_header(new_resp.headers) if new_resp.body is not None: response.write_body(new_resp.body) # Dep impl - the handler is provided with a req & resp writer else: with request_context(request.tracing): f = handler.endpoint(request, response) yield gen.maybe_future(f) response.flush() except TChannelError as e: e.tracing = request.tracing e.id = request.id connection.send_error(e) except Exception as e: error = UnexpectedError( description="Unexpected Error: '%s'" % e.message, id=request.id, tracing=request.tracing, ) response.set_exception(error) connection.request_message_factory.remove_buffer(response.id) connection.send_error(error) tchannel.event_emitter.fire(EventType.on_exception, request, error) log.exception(error.description) raise gen.Return(response)
def handle_call(self, request, connection): # read arg_1 so that handle_call is able to get the endpoint # name and find the endpoint handler. # the arg_1 value will be store in the request.endpoint field. # NOTE: after here, the correct way to access value of arg_1 is through # request.endpoint. The original argstream[0] is no longer valid. If # user still tries read from it, it will return empty. chunk = yield request.argstreams[0].read() while chunk: request.endpoint += chunk chunk = yield request.argstreams[0].read() log.debug("Received a call to %s.", request.endpoint) tchannel = connection.tchannel tchannel.event_emitter.fire(EventType.before_receive_request, request) handler = self.get_endpoint(request.endpoint) requested_as = request.headers.get("as", None) expected_as = handler.req_serializer.name if request.endpoint in self.handlers and requested_as != expected_as: connection.send_error( BadRequestError( description=("Server expected a '%s' but request is '%s'" % (expected_as, requested_as)), id=request.id, tracing=request.tracing, ) ) raise gen.Return(None) request.serializer = handler.req_serializer response = DeprecatedResponse( id=request.id, checksum=request.checksum, tracing=request.tracing, connection=connection, headers={"as": request.headers.get("as", "raw")}, serializer=handler.resp_serializer, ) def _on_post_response(future): if not future.exception(): return # Failed to write response because client disappeared. Nothing to # do. if isinstance(future.exception(), StreamClosedError): return log.error("failed to write response", exc_info=future.exc_info()) connection.post_response(response).add_done_callback(_on_post_response) tracer = tracing.ServerTracer(tracer=tchannel.tracer, operation_name=request.endpoint) tracer.start_basic_span(request) try: # New impl - the handler takes a request and returns a response if self._handler_returns_response: # convert deprecated req to new top-level req b = yield request.get_body() he = yield request.get_header() t = TransportHeaders.from_dict(request.headers) new_req = Request( body=b, headers=he, transport=t, endpoint=request.endpoint, service=request.service, timeout=request.ttl, ) with tracer.start_span( request=request, headers=he, peer_host=connection.remote_host, peer_port=connection.remote_host_port ) as span: context_provider = tchannel.context_provider_fn() with context_provider.span_in_context(span): # Cannot yield while inside the StackContext f = handler.endpoint(new_req) new_resp = yield gen.maybe_future(f) # instantiate a tchannel.Response new_resp = response_from_mixed(new_resp) response.code = new_resp.status # assign resp values to dep response response.write_header(new_resp.headers) if new_resp.body is not None: response.write_body(new_resp.body) # Dep impl - the handler is provided with a req & resp writer else: with tracer.start_span( request=request, headers={}, peer_host=connection.remote_host, peer_port=connection.remote_host_port ) as span: context_provider = tchannel.context_provider_fn() with context_provider.span_in_context(span): # Cannot yield while inside the StackContext f = handler.endpoint(request, response) yield gen.maybe_future(f) response.flush() except TChannelError as e: e.tracing = request.tracing e.id = request.id connection.send_error(e) except Exception as e: # Maintain a reference to our original exc info because we stomp # the traceback below. exc_info = sys.exc_info() exc_type, exc_obj, exc_tb = exc_info try: # Walk to the traceback to find our offending line. while exc_tb.tb_next is not None: exc_tb = exc_tb.tb_next description = "%r from %s in %s:%s" % ( e, request.endpoint, exc_tb.tb_frame.f_code.co_filename, exc_tb.tb_lineno, ) error = UnexpectedError(description=description, id=request.id, tracing=request.tracing) response.set_exception(error, exc_info=exc_info) connection.request_message_factory.remove_buffer(response.id) connection.send_error(error) tchannel.event_emitter.fire(EventType.on_exception, request, error) log.error("Unexpected error", exc_info=exc_info) finally: # Clean up circular reference. # https://docs.python.org/2/library/sys.html#sys.exc_info del exc_tb del exc_info raise gen.Return(response)
def handle_call(self, request, connection): # read arg_1 so that handle_call is able to get the endpoint # name and find the endpoint handler. # the arg_1 value will be store in the request.endpoint field. # NOTE: after here, the correct way to access value of arg_1 is through # request.endpoint. The original argstream[0] is no longer valid. If # user still tries read from it, it will return empty. chunk = yield request.argstreams[0].read() response = None while chunk: request.endpoint += chunk chunk = yield request.argstreams[0].read() log.debug('Received a call to %s.', request.endpoint) tchannel = connection.tchannel # event: receive_request request.tracing.name = request.endpoint tchannel.event_emitter.fire(EventType.before_receive_request, request) handler = self.handlers.get(request.endpoint) if handler is None: handler = self.handlers[self.FALLBACK] if request.headers.get('as', None) != handler.req_serializer.name: connection.send_error( ErrorCode.bad_request, "Invalid arg scheme in request header", request.id, ) raise gen.Return(None) request.serializer = handler.req_serializer response = DeprecatedResponse( id=request.id, checksum=request.checksum, tracing=request.tracing, connection=connection, headers={'as': request.headers.get('as', 'raw')}, serializer=handler.resp_serializer, ) connection.post_response(response) try: # New impl - the handler takes a request and returns a response if self._handler_returns_response: # convert deprecated req to new top-level req b = yield request.get_body() he = yield request.get_header() t = request.headers t = transport.to_kwargs(t) t = TransportHeaders(**t) new_req = Request( body=b, headers=he, transport=t, endpoint=request.endpoint, ) # Not safe to have coroutine yields statement within # stack context. # The right way to do it is: # with request_context(..): # future = f() # yield future with request_context(request.tracing): f = handler.endpoint(new_req) new_resp = yield gen.maybe_future(f) # instantiate a tchannel.Response new_resp = response_from_mixed(new_resp) # assign resp values to dep response response.write_header(new_resp.headers) if new_resp.body is not None: response.write_body(new_resp.body) # Dep impl - the handler is provided with a req & resp writer else: with request_context(request.tracing): f = handler.endpoint(request, response) yield gen.maybe_future(f) response.flush() except TChannelError as e: connection.send_error( e.code, e.message, request.id, ) except Exception as e: msg = "An unexpected error has occurred from the handler" log.exception(msg) response.set_exception(TChannelError(e.message)) connection.request_message_factory.remove_buffer(response.id) connection.send_error(ErrorCode.unexpected, msg, response.id) tchannel.event_emitter.fire(EventType.on_exception, request, e) raise gen.Return(response)
def handle_call(self, request, connection): # read arg_1 so that handle_call is able to get the endpoint # name and find the endpoint handler. # the arg_1 value will be store in the request.endpoint field. # NOTE: after here, the correct way to access value of arg_1 is through # request.endpoint. The original argstream[0] is no longer valid. If # user still tries read from it, it will return empty. chunk = yield request.argstreams[0].read() response = None while chunk: request.endpoint += chunk chunk = yield request.argstreams[0].read() log.debug('Received a call to %s.', request.endpoint) tchannel = connection.tchannel # event: receive_request request.tracing.name = request.endpoint tchannel.event_emitter.fire(EventType.before_receive_request, request) handler = self.get_endpoint(request.endpoint) requested_as = request.headers.get('as', None) expected_as = handler.req_serializer.name if request.endpoint in self.handlers and requested_as != expected_as: connection.send_error(BadRequestError( description=( "Server expected a '%s' but request is '%s'" % ( expected_as, requested_as, ) ), id=request.id, tracing=request.tracing, )) raise gen.Return(None) request.serializer = handler.req_serializer response = DeprecatedResponse( id=request.id, checksum=request.checksum, tracing=request.tracing, connection=connection, headers={'as': request.headers.get('as', 'raw')}, serializer=handler.resp_serializer, ) def _on_post_response(future): if not future.exception(): return # Failed to write response because client disappeared. Nothing to # do. if isinstance(future.exception(), StreamClosedError): return log.error('failed to write response', exc_info=future.exc_info()) connection.post_response(response).add_done_callback(_on_post_response) try: # New impl - the handler takes a request and returns a response if self._handler_returns_response: # convert deprecated req to new top-level req b = yield request.get_body() he = yield request.get_header() t = TransportHeaders.from_dict(request.headers) new_req = Request( body=b, headers=he, transport=t, endpoint=request.endpoint, service=request.service, timeout=request.ttl, ) # Not safe to have coroutine yields statement within # stack context. # The right way to do it is: # with request_context(..): # future = f() # yield future with request_context(request.tracing): f = handler.endpoint(new_req) new_resp = yield gen.maybe_future(f) # instantiate a tchannel.Response new_resp = response_from_mixed(new_resp) response.code = new_resp.status # assign resp values to dep response response.write_header(new_resp.headers) if new_resp.body is not None: response.write_body(new_resp.body) # Dep impl - the handler is provided with a req & resp writer else: with request_context(request.tracing): f = handler.endpoint(request, response) yield gen.maybe_future(f) response.flush() except TChannelError as e: e.tracing = request.tracing e.id = request.id connection.send_error(e) except Exception as e: # Maintain a reference to our original exc info because we stomp # the traceback below. exc_info = sys.exc_info() exc_type, exc_obj, exc_tb = exc_info try: # Walk to the traceback to find our offending line. while exc_tb.tb_next is not None: exc_tb = exc_tb.tb_next description = "%r from %s in %s:%s" % ( e, request.endpoint, exc_tb.tb_frame.f_code.co_filename, exc_tb.tb_lineno, ) error = UnexpectedError( description=description, id=request.id, tracing=request.tracing, ) response.set_exception(error, exc_info=exc_info) connection.request_message_factory.remove_buffer(response.id) connection.send_error(error) tchannel.event_emitter.fire( EventType.on_exception, request, error, ) log.error("Unexpected error", exc_info=exc_info) finally: # Clean up circular reference. # https://docs.python.org/2/library/sys.html#sys.exc_info del exc_tb del exc_info raise gen.Return(response)
def handle_call(self, request, connection): # read arg_1 so that handle_call is able to get the endpoint # name and find the endpoint handler. # the arg_1 value will be store in the request.endpoint field. # NOTE: after here, the correct way to access value of arg_1 is through # request.endpoint. The original argstream[0] is no longer valid. If # user still tries read from it, it will return empty. chunk = yield request.argstreams[0].read() response = None while chunk: request.endpoint += chunk chunk = yield request.argstreams[0].read() log.debug('Received a call to %s.', request.endpoint) tchannel = connection.tchannel # event: receive_request request.tracing.name = request.endpoint tchannel.event_emitter.fire(EventType.before_receive_request, request) handler = self.handlers[request.endpoint] if request.headers.get('as', None) != handler.req_serializer.name: connection.send_error( ErrorCode.bad_request, "Invalid arg scheme in request header", request.id, ) raise gen.Return(None) request.serializer = handler.req_serializer response = DeprecatedResponse( id=request.id, checksum=request.checksum, tracing=request.tracing, connection=connection, headers={'as': request.headers.get('as', 'raw')}, serializer=handler.resp_serializer, ) connection.post_response(response) try: # New impl - the handler takes a request and returns a response if self._handler_returns_response: # convert deprecated req to new top-level req b = yield request.get_body() he = yield request.get_header() t = request.headers t = transport.to_kwargs(t) t = TransportHeaders(**t) new_req = Request( body=b, headers=he, transport=t, ) # Not safe to have coroutine yields statement within # stack context. # The right way to do it is: # with request_context(..): # future = f() # yield future with request_context(request.tracing): f = handler.endpoint(new_req) new_resp = yield gen.maybe_future(f) # instantiate a tchannel.Response new_resp = response_from_mixed(new_resp) # assign resp values to dep response response.write_header(new_resp.headers) if new_resp.body is not None: response.write_body(new_resp.body) # Dep impl - the handler is provided with a req & resp writer else: with request_context(request.tracing): f = handler.endpoint(request, response) yield gen.maybe_future(f) response.flush() except InvalidEndpointError as e: connection.send_error( ErrorCode.bad_request, e.message, request.id, ) except Exception as e: msg = "An unexpected error has occurred from the handler" log.exception(msg) response.set_exception(TChannelError(e.message)) connection.request_message_factory.remove_buffer(response.id) connection.send_error(ErrorCode.unexpected, msg, response.id) tchannel.event_emitter.fire(EventType.on_exception, request, e) raise gen.Return(response)