Skip to content

Commit 3d4ee51

Browse files
Merge pull request #162 from skyflowapi/SK-1906-improve-debugging-errors-in-connections
SK-1906 Improve debugging in connections
2 parents 6ee1883 + 9cd613b commit 3d4ee51

File tree

5 files changed

+53
-22
lines changed

5 files changed

+53
-22
lines changed

skyflow/utils/_skyflow_messages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ class ErrorLogs(Enum):
277277
UPDATE_REQUEST_REJECTED = f"{ERROR}: [{error_prefix}] Update request resulted in failure."
278278
QUERY_REQUEST_REJECTED = f"{ERROR}: [{error_prefix}] Query request resulted in failure."
279279
GET_REQUEST_REJECTED = f"{ERROR}: [{error_prefix}] Get request resulted in failure."
280+
INVOKE_CONNECTION_REQUEST_REJECTED = f"{ERROR}: [{error_prefix}] Invoke connection request resulted in failure."
280281

281282
class Interface(Enum):
282283
INSERT = "INSERT"

skyflow/utils/_utils.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -327,24 +327,30 @@ def parse_invoke_connection_response(api_response: requests.Response):
327327

328328
invoke_connection_response.response = json_content
329329
return invoke_connection_response
330-
except:
330+
except Exception as e:
331331
raise SkyflowError(SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format(content), status_code)
332332
except HTTPError:
333-
message = SkyflowMessages.Error.API_ERROR.value.format(status_code)
334-
if api_response and api_response.content:
335-
try:
336-
error_response = json.loads(content)
337-
if isinstance(error_response.get('error'), dict) and 'message' in error_response['error']:
338-
message = error_response['error']['message']
339-
except json.JSONDecodeError:
340-
message = SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format(content)
341-
342-
if 'x-request-id' in api_response.headers:
343-
message += ' - request id: ' + api_response.headers['x-request-id']
344-
333+
message = SkyflowMessages.Error.API_ERROR.value.format(status_code)
334+
try:
335+
error_response = json.loads(content)
336+
request_id = api_response.headers['x-request-id']
337+
error_from_client = api_response.headers.get('error-from-client')
338+
339+
status_code = error_response.get('error', {}).get('http_code', 500) # Default to 500 if not found
340+
http_status = error_response.get('error', {}).get('http_status')
341+
grpc_code = error_response.get('error', {}).get('grpc_code')
342+
details = error_response.get('error', {}).get('details')
343+
message = error_response.get('error', {}).get('message', "An unknown error occurred.")
344+
345+
if error_from_client is not None:
346+
if details is None: details = []
347+
details.append({'error_from_client': error_from_client})
348+
349+
raise SkyflowError(message, status_code, request_id, grpc_code, http_status, details)
350+
except json.JSONDecodeError:
351+
message = SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format(content)
345352
raise SkyflowError(message, status_code)
346353

347-
348354
def log_and_reject_error(description, status_code, request_id, http_status=None, grpc_code=None, details=None, logger = None):
349355
raise SkyflowError(description, status_code, request_id, grpc_code, http_status, details)
350356

skyflow/vault/controller/_connections.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from skyflow.error import SkyflowError
44
from skyflow.utils import construct_invoke_connection_request, SkyflowMessages, get_metrics, \
55
parse_invoke_connection_response
6-
from skyflow.utils.logger import log_info
6+
from skyflow.utils.logger import log_info, log_error_log
77
from skyflow.vault.connection import InvokeConnectionRequest
88

99

@@ -27,7 +27,7 @@ def invoke(self, request: InvokeConnectionRequest):
2727

2828
invoke_connection_request.headers['sky-metadata'] = json.dumps(get_metrics())
2929

30-
log_info(SkyflowMessages.Info.INVOKE_CONNECTION_TRIGGERED, self.__vault_client.get_logger())
30+
log_info(SkyflowMessages.Info.INVOKE_CONNECTION_TRIGGERED.value, self.__vault_client.get_logger())
3131

3232
try:
3333
response = session.send(invoke_connection_request)
@@ -36,5 +36,7 @@ def invoke(self, request: InvokeConnectionRequest):
3636
return invoke_connection_response
3737

3838
except Exception as e:
39+
log_error_log(SkyflowMessages.ErrorLogs.INVOKE_CONNECTION_REQUEST_REJECTED.value, self.__vault_client.get_logger())
40+
if isinstance(e, SkyflowError): raise e
3941
raise SkyflowError(SkyflowMessages.Error.INVOKE_CONNECTION_FAILED.value,
4042
SkyflowMessages.ErrorCodes.SERVER_ERROR.value)

tests/utils/test__utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ def test_parse_invoke_connection_response_http_error_with_json_error_message(sel
344344
with self.assertRaises(SkyflowError) as context:
345345
parse_invoke_connection_response(mock_response)
346346

347-
self.assertEqual(context.exception.message, "Not Found - request id: 1234")
347+
self.assertEqual(context.exception.message, "Not Found")
348+
self.assertEqual(context.exception.request_id, "1234")
348349

349350
@patch("requests.Response")
350351
def test_parse_invoke_connection_response_http_error_without_json_error_message(self, mock_response):
@@ -357,7 +358,7 @@ def test_parse_invoke_connection_response_http_error_without_json_error_message(
357358
with self.assertRaises(SkyflowError) as context:
358359
parse_invoke_connection_response(mock_response)
359360

360-
self.assertEqual(context.exception.message, SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format("Internal Server Error") + " - request id: 1234")
361+
self.assertEqual(context.exception.message, SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format("Internal Server Error"))
361362

362363
@patch("skyflow.utils._utils.log_and_reject_error")
363364
def test_handle_exception_json_error(self, mock_log_and_reject_error):

tests/vault/controller/test__connection.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import unittest
22
from unittest.mock import Mock, patch
3-
3+
import requests
44
from skyflow.error import SkyflowError
5-
from skyflow.utils import SkyflowMessages
5+
from skyflow.utils import SkyflowMessages, parse_invoke_connection_response
66
from skyflow.utils.enums import RequestMethod
7+
from skyflow.utils._version import SDK_VERSION
78
from skyflow.vault.connection import InvokeConnectionRequest
89
from skyflow.vault.controller import Connection
910

@@ -21,7 +22,8 @@
2122
INVALID_HEADERS = "invalid_headers"
2223
INVALID_BODY = "invalid_body"
2324
FAILURE_STATUS_CODE = 400
24-
ERROR_RESPONSE_CONTENT = '{"error": {"message": "error occurred"}}'
25+
ERROR_RESPONSE_CONTENT = '"message": "Invalid Request"'
26+
ERROR_FROM_CLIENT_RESPONSE_CONTENT = b'{"error": {"message": "Invalid Request"}}'
2527

2628
class TestConnection(unittest.TestCase):
2729
def setUp(self):
@@ -99,6 +101,25 @@ def test_invoke_request_error(self, mock_send):
99101

100102
with self.assertRaises(SkyflowError) as context:
101103
self.connection.invoke(request)
102-
self.assertEqual(context.exception.message, SkyflowMessages.Error.INVOKE_CONNECTION_FAILED.value)
104+
self.assertEqual(context.exception.message, f'Skyflow Python SDK {SDK_VERSION} Response {ERROR_RESPONSE_CONTENT} is not valid JSON.')
105+
self.assertEqual(context.exception.message, SkyflowMessages.Error.RESPONSE_NOT_JSON.value.format(ERROR_RESPONSE_CONTENT))
106+
self.assertEqual(context.exception.http_code, 400)
107+
108+
def test_parse_invoke_connection_response_error_from_client(self):
109+
mock_response = Mock(spec=requests.Response)
110+
mock_response.status_code = FAILURE_STATUS_CODE
111+
mock_response.content = ERROR_FROM_CLIENT_RESPONSE_CONTENT
112+
mock_response.headers = {
113+
'error-from-client': 'true',
114+
'x-request-id': '12345'
115+
}
116+
mock_response.raise_for_status.side_effect = requests.HTTPError()
117+
118+
with self.assertRaises(SkyflowError) as context:
119+
parse_invoke_connection_response(mock_response)
120+
121+
exception = context.exception
103122

123+
self.assertTrue(any(detail.get('error_from_client') == 'true' for detail in exception.details))
124+
self.assertEqual(exception.request_id, '12345')
104125

0 commit comments

Comments
 (0)