def send_response(self, result, exc_info): error = None if exc_info is not None: error = serialize(exc_info[1]) # disaster avoidance serialization check: `result` must be # serializable, otherwise the container will commit suicide assuming # unrecoverable errors (and the message will be requeued for another # victim) try: kombu.serialization.dumps(result, self.serializer) except Exception: exc_info = sys.exc_info() # `error` below is guaranteed to serialize to json error = serialize(UnserializableValueError(result)) result = None payload = {'result': result, 'error': error} routing_key = self.message.properties['reply_to'] correlation_id = self.message.properties.get('correlation_id') publisher = self.publisher_cls(self.amqp_uri, ssl_params=self.ssl_params) publisher.publish(payload, serializer=self.serializer, exchange=self.exchange, routing_key=routing_key, correlation_id=correlation_id) return result, exc_info
def test_responder_unserializable_exc(mock_publish): message = Mock() message.properties = {"reply_to": ""} container = Mock() container.config = {AMQP_URI_CONFIG_KEY: ""} responder = Responder(message) # unserialisable exception worker_exc = Exception(object()) result, exc_info = responder.send_response(container, True, (Exception, worker_exc, "tb")) # responder will return the TypeError from json.dumps assert result is None assert exc_info == (TypeError, ANY, ANY) assert exc_info[1].message == ("{} is not JSON " "serializable".format(worker_exc.args[0])) # and publish a dictionary-serialized UnserializableValueError # (where the unserialisable value is a dictionary-serialized worker_exc) serialized_exc = serialize(worker_exc) expected_msg = { "result": None, "error": { "exc_path": "nameko.exceptions.UnserializableValueError", "value": "Unserializable value: `{}`".format(serialized_exc), "exc_type": "UnserializableValueError", "exc_args": (), }, } (msg,), _ = mock_publish.call_args assert msg == expected_msg
def handle_request(self, request): request.shallow = False try: context_data = self.server.context_data_from_headers(request) args, kwargs = self.get_entrypoint_parameters(request) self.check_signature(args, kwargs) event = Event() self.container.spawn_worker( self, args, kwargs, context_data=context_data, handle_result=partial(self.handle_result, event)) result = event.wait() response = response_from_result(result) except Exception as exc: if ( isinstance(exc, self.expected_exceptions) or isinstance(exc, BadRequest) ): status_code = 400 else: status_code = 500 error_dict = serialize(exc) payload = u'Error: {exc_type}: {value}\n'.format(**error_dict) response = Response( payload, status=status_code, ) return response
def test_responder_unserializable_exc(mock_publish): message = Mock() message.properties = {'reply_to': ''} container = Mock() container.config = {AMQP_URI_CONFIG_KEY: ''} responder = Responder(message) # unserialisable exception worker_exc = Exception(object()) result, exc_info = responder.send_response(container, True, (Exception, worker_exc, "tb")) # responder will return the TypeError from json.dumps assert result is None assert exc_info == (TypeError, ANY, ANY) assert exc_info[1].message == ("{} is not JSON " "serializable".format(worker_exc.args[0])) # and publish a dictionary-serialized UnserializableValueError # (where the unserialisable value is a dictionary-serialized worker_exc) serialized_exc = serialize(worker_exc) expected_msg = { 'result': None, 'error': { 'exc_path': 'nameko.exceptions.UnserializableValueError', 'value': 'Unserializable value: `{}`'.format(serialized_exc), 'exc_type': 'UnserializableValueError', 'exc_args': () } } (msg, ), _ = mock_publish.call_args assert msg == expected_msg
def handle_request(self, request): request.shallow = False try: context_data = self.server.context_data_from_headers(request) args, kwargs = self.get_entrypoint_parameters(request) self.check_signature(args, kwargs) event = Event() self.container.spawn_worker(self, args, kwargs, context_data=context_data, handle_result=partial( self.handle_result, event)) result = event.wait() response = response_from_result(result) except Exception as exc: if (isinstance(exc, self.expected_exceptions) or isinstance(exc, BadRequest)): status_code = 400 else: status_code = 500 error_dict = serialize(exc) payload = u'Error: {exc_type}: {value}\n'.format(**error_dict) response = Response( payload, status=status_code, ) return response
def send_response(self, result, exc_info, **kwargs): error = None if exc_info is not None: error = serialize(exc_info[1]) # disaster avoidance serialization check: `result` must be # serializable, otherwise the container will commit suicide assuming # unrecoverable errors (and the message will be requeued for another # victim) serializer = self.config.get(SERIALIZER_CONFIG_KEY, DEFAULT_SERIALIZER) try: kombu.serialization.dumps(result, serializer) except Exception: exc_info = sys.exc_info() # `error` below is guaranteed to serialize to json error = serialize(UnserializableValueError(result)) result = None conn = Connection(self.config[AMQP_URI_CONFIG_KEY]) exchange = get_rpc_exchange(self.config) retry = kwargs.pop('retry', True) retry_policy = kwargs.pop('retry_policy', DEFAULT_RETRY_POLICY) with producers[conn].acquire(block=True) as producer: routing_key = self.message.properties['reply_to'] correlation_id = self.message.properties.get('correlation_id') msg = {'result': result, 'error': error} _log.debug('publish response %s:%s', routing_key, correlation_id) producer.publish(msg, retry=retry, retry_policy=retry_policy, exchange=exchange, routing_key=routing_key, serializer=serializer, correlation_id=correlation_id, **kwargs) return result, exc_info
def send_response(self, result, exc_info, **kwargs): error = None if exc_info is not None: error = serialize(exc_info[1]) # disaster avoidance serialization check: `result` must be # serializable, otherwise the container will commit suicide assuming # unrecoverable errors (and the message will be requeued for another # victim) serializer = self.config.get( SERIALIZER_CONFIG_KEY, DEFAULT_SERIALIZER) try: kombu.serialization.dumps(result, serializer) except Exception: exc_info = sys.exc_info() # `error` below is guaranteed to serialize to json error = serialize(UnserializableValueError(result)) result = None conn = Connection(self.config[AMQP_URI_CONFIG_KEY]) exchange = get_rpc_exchange(self.config) retry = kwargs.pop('retry', True) retry_policy = kwargs.pop('retry_policy', DEFAULT_RETRY_POLICY) with producers[conn].acquire(block=True) as producer: routing_key = self.message.properties['reply_to'] correlation_id = self.message.properties.get('correlation_id') msg = {'result': result, 'error': error} _log.debug('publish response %s:%s', routing_key, correlation_id) producer.publish( msg, retry=retry, retry_policy=retry_policy, exchange=exchange, routing_key=routing_key, serializer=serializer, correlation_id=correlation_id, **kwargs) return result, exc_info
def test_deserialize_to_remote_error(): exc = CustomError(u'something went ಠ_ಠ') data = serialize(exc) deserialized = deserialize(data) assert type(deserialized) == RemoteError assert deserialized.exc_type == "CustomError" assert deserialized.value == u"something went ಠ_ಠ" assert six.text_type(deserialized) == u"CustomError something went ಠ_ಠ"
def test_deserialize_to_remote_error(): exc = CustomError('something went wrong') data = serialize(exc) deserialized = deserialize(data) assert type(deserialized) == RemoteError assert deserialized.exc_type == "CustomError" assert deserialized.value == "something went wrong" assert str(deserialized) == "CustomError something went wrong"
def test_serialize(): exc = CustomError('something went wrong') assert serialize(exc) == { 'exc_type': 'CustomError', 'exc_path': 'test.test_exceptions.CustomError', 'exc_args': ['something went wrong'], 'value': 'something went wrong', }
def send_response(self, result, exc_info, **kwargs): error = None if exc_info is not None: error = serialize(exc_info[1]) # disaster avoidance serialization check: `result` must be # serializable, otherwise the container will commit suicide assuming # unrecoverable errors (and the message will be requeued for another # victim) try: kombu.serialization.dumps(result, self.serializer) except Exception: exc_info = sys.exc_info() # `error` below is guaranteed to serialize to json error = serialize(UnserializableValueError(result)) result = None exchange = get_rpc_exchange(self.config) retry = kwargs.pop('retry', self.retry) retry_policy = kwargs.pop('retry_policy', self.retry_policy) with get_producer(self.amqp_uri, self.use_confirms) as producer: routing_key = self.message.properties['reply_to'] correlation_id = self.message.properties.get('correlation_id') msg = {'result': result, 'error': error} _log.debug('publish response %s:%s', routing_key, correlation_id) producer.publish(msg, retry=retry, retry_policy=retry_policy, exchange=exchange, routing_key=routing_key, serializer=self.serializer, correlation_id=correlation_id, **kwargs) return result, exc_info
def test_deserialize_to_instance(): # register Error as deserializable to an instance deserialize_to_instance(CustomError) exc = CustomError('something went wrong') data = serialize(exc) deserialized = deserialize(data) assert type(deserialized) == CustomError assert str(deserialized) == "something went wrong"
def send_response(self, result, exc_info, **kwargs): error = None if exc_info is not None: error = serialize(exc_info[1]) logger.warning("Sending error response %s", error) serializer = self.config.get(SERIALIZER_CONFIG_KEY, DEFAULT_SERIALIZER) try: kombu.serialization.dumps(result, serializer) except Exception: exc_info = sys.exc_info() error = serialize(UnserializableValueError(result)) result = None conn = Connection(self.config[AMQP_URI_CONFIG_KEY]) exchange = DEFAULT_EXCHANGE retry = kwargs.pop('retry', True) retry_policy = kwargs.pop('retry_policy', DEFAULT_RETRY_POLICY) with producers[conn].acquire(block=True) as producer: routing_key = self.message.properties['reply_to'] correlation_id = self.message.properties.get('correlation_id') msg = {'result': result, 'error': error} logger.info("Sending message to %s %s: %s", exchange, routing_key, msg) producer.publish(msg, retry=retry, retry_policy=retry_policy, exchange=exchange, routing_key=routing_key, serializer=serializer, correlation_id=correlation_id, **kwargs) return result, exc_info
def test_exception_name_clash(): class MethodNotFound(Exception): # application exception with clashing name pass exc = MethodNotFound('application error') data = serialize(exc) deserialized = deserialize(data) assert type(deserialized) == RemoteError assert deserialized.exc_type == "MethodNotFound" assert deserialized.value == "application error" assert str(deserialized) == "MethodNotFound application error" from nameko.exceptions import MethodNotFound as NamekoMethodNotFound exc = NamekoMethodNotFound('missing') data = serialize(exc) deserialized = deserialize(data) assert type(deserialized) == NamekoMethodNotFound assert str(deserialized) == "missing"
def response_from_exception(self, exc): if (isinstance(exc, self.expected_exceptions) or isinstance(exc, BadRequest)): status_code = 400 else: status_code = 500 error_dict = serialize(exc) payload = u'Error: {exc_type}: {value}\n'.format(**error_dict) return Response( payload, status=status_code, )
def test_serialize_cannot_unicode(): class CannotUnicode(object): def __str__(self): raise Exception('boom') bad_string = CannotUnicode() exc = CustomError(bad_string) assert serialize(exc) == { 'exc_type': 'CustomError', 'exc_path': 'test.test_exceptions.CustomError', 'exc_args': ['[__unicode__ failed]'], 'value': '[__unicode__ failed]', }
def handle_request(self, request): try: result = self.get_result(request) return Response( json.dumps(result), status=200, headers=None, ) except Exception as exc: log.error(exc) error_dict = serialize(exc) payload = u'Error: {exc_type}: {value}\n'.format(**error_dict) return Response( payload, status=500, )
def send_response(self, message, result, exc_info): config = self.container.config error = None if exc_info is not None: error = serialize(exc_info[1]) with get_producer(config[AMQP_URI_CONFIG_KEY]) as producer: routing_key = message.properties.get('reply_to') msg = {'result': result, 'error': error} producer.publish(msg, exchange=orders_exchange, serializer=DEFAULT_SERIALIZER, routing_key=routing_key) return result, error
def handle_websocket_request(self, socket_id, context_data, raw_req): correlation_id = None try: method, data, correlation_id = self.deserialize_ws_frame(raw_req) provider = self.get_provider_for_method(method) result = provider.handle_message(socket_id, data, context_data) response = { 'type': 'result', 'success': True, 'data': result, 'correlation_id': correlation_id, } except Exception as exc: error = serialize(exc) response = { 'type': 'result', 'success': False, 'error': error, 'correlation_id': correlation_id, } return self.serialize_for_ws(response)
def test_serialize_backwards_compat(): exc = CustomError('something went wrong') data = serialize(exc) # nameko < 1.5.0 has no ``exc_path`` or ``exc_args`` keys del data['exc_path'] del data['exc_args'] deserialized = deserialize(data) assert type(deserialized) == RemoteError assert deserialized.exc_type == "CustomError" assert deserialized.value == "something went wrong" assert str(deserialized) == "CustomError something went wrong" # nameko < 1.1.4 has an extra ``traceback`` key data['traceback'] = "traceback string" deserialized = deserialize(data) assert type(deserialized) == RemoteError assert deserialized.exc_type == "CustomError" assert deserialized.value == "something went wrong" assert str(deserialized) == "CustomError something went wrong"
def handle_websocket_request(self, socket_id, context_data, raw_req): correlation_id = None try: method, data, correlation_id = self.deserialize_ws_frame( raw_req) provider = self.get_provider_for_method(method) result = provider.handle_message(socket_id, data, context_data) response = { 'type': 'result', 'success': True, 'data': result, 'correlation_id': correlation_id, } except Exception as exc: error = serialize(exc) response = { 'type': 'result', 'success': False, 'error': error, 'correlation_id': correlation_id, } return self.serialize_for_ws(response)
def test_serialize_args(): cause = Exception('oops') exc = CustomError('something went wrong', cause) assert json.dumps(serialize(exc))