Skip to content

Commit

Permalink
Merge branch 'main' into update-durabletask-fork
Browse files Browse the repository at this point in the history
  • Loading branch information
elena-kolevska authored Jan 13, 2025
2 parents 296de6c + 0f6e96a commit faebc7a
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 14 deletions.
12 changes: 12 additions & 0 deletions dapr/clients/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
import base64
import json
from typing import Optional

Expand Down Expand Up @@ -44,6 +45,17 @@ def as_dict(self):
'raw_response_bytes': self._raw_response_bytes,
}

def as_json_safe_dict(self):
error_dict = self.as_dict()

if self._raw_response_bytes is not None:
# Encode bytes to base64 for JSON compatibility
error_dict['raw_response_bytes'] = base64.b64encode(self._raw_response_bytes).decode(
'utf-8'
)

return error_dict


class StatusDetails:
def __init__(self):
Expand Down
15 changes: 7 additions & 8 deletions ext/dapr-ext-fastapi/dapr/ext/fastapi/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@

from typing import Any, Optional, Type, List

from dapr.actor import Actor, ActorRuntime
from dapr.clients.exceptions import ERROR_CODE_UNKNOWN, DaprInternalError
from dapr.serializers import DefaultJSONSerializer
from fastapi import FastAPI, APIRouter, Request, Response, status # type: ignore
from fastapi.logger import logger
from fastapi.responses import JSONResponse

from dapr.actor import Actor, ActorRuntime
from dapr.clients.exceptions import DaprInternalError, ERROR_CODE_UNKNOWN
from dapr.serializers import DefaultJSONSerializer

DEFAULT_CONTENT_TYPE = 'application/json; utf-8'
DAPR_REENTRANCY_ID_HEADER = 'Dapr-Reentrancy-Id'

Expand Down Expand Up @@ -72,7 +71,7 @@ async def actor_deactivation(actor_type_name: str, actor_id: str):
try:
await ActorRuntime.deactivate(actor_type_name, actor_id)
except DaprInternalError as ex:
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_dict())
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_json_safe_dict())
except Exception as ex:
return _wrap_response(
status.HTTP_500_INTERNAL_SERVER_ERROR, repr(ex), ERROR_CODE_UNKNOWN
Expand All @@ -96,7 +95,7 @@ async def actor_method(
actor_type_name, actor_id, method_name, req_body, reentrancy_id
)
except DaprInternalError as ex:
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_dict())
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_json_safe_dict())
except Exception as ex:
return _wrap_response(
status.HTTP_500_INTERNAL_SERVER_ERROR, repr(ex), ERROR_CODE_UNKNOWN
Expand All @@ -117,7 +116,7 @@ async def actor_timer(
req_body = await request.body()
await ActorRuntime.fire_timer(actor_type_name, actor_id, timer_name, req_body)
except DaprInternalError as ex:
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_dict())
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_json_safe_dict())
except Exception as ex:
return _wrap_response(
status.HTTP_500_INTERNAL_SERVER_ERROR, repr(ex), ERROR_CODE_UNKNOWN
Expand All @@ -139,7 +138,7 @@ async def actor_reminder(
req_body = await request.body()
await ActorRuntime.fire_reminder(actor_type_name, actor_id, reminder_name, req_body)
except DaprInternalError as ex:
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_dict())
return _wrap_response(status.HTTP_500_INTERNAL_SERVER_ERROR, ex.as_json_safe_dict())
except Exception as ex:
return _wrap_response(
status.HTTP_500_INTERNAL_SERVER_ERROR, repr(ex), ERROR_CODE_UNKNOWN
Expand Down
10 changes: 5 additions & 5 deletions ext/flask_dapr/flask_dapr/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from flask import jsonify, make_response, request

from dapr.actor import Actor, ActorRuntime
from dapr.clients.exceptions import DaprInternalError, ERROR_CODE_UNKNOWN
from dapr.clients.exceptions import ERROR_CODE_UNKNOWN, DaprInternalError
from dapr.serializers import DefaultJSONSerializer

DEFAULT_CONTENT_TYPE = 'application/json; utf-8'
Expand Down Expand Up @@ -80,7 +80,7 @@ def _deactivation_handler(self, actor_type_name, actor_id):
try:
asyncio.run(ActorRuntime.deactivate(actor_type_name, actor_id))
except DaprInternalError as ex:
return wrap_response(500, ex.as_dict())
return wrap_response(500, ex.as_json_safe_dict())
except Exception as ex:
return wrap_response(500, repr(ex), ERROR_CODE_UNKNOWN)

Expand All @@ -99,7 +99,7 @@ def _method_handler(self, actor_type_name, actor_id, method_name):
)
)
except DaprInternalError as ex:
return wrap_response(500, ex.as_dict())
return wrap_response(500, ex.as_json_safe_dict())
except Exception as ex:
return wrap_response(500, repr(ex), ERROR_CODE_UNKNOWN)

Expand All @@ -113,7 +113,7 @@ def _timer_handler(self, actor_type_name, actor_id, timer_name):
req_body = request.stream.read()
asyncio.run(ActorRuntime.fire_timer(actor_type_name, actor_id, timer_name, req_body))
except DaprInternalError as ex:
return wrap_response(500, ex.as_dict())
return wrap_response(500, ex.as_json_safe_dict())
except Exception as ex:
return wrap_response(500, repr(ex), ERROR_CODE_UNKNOWN)

Expand All @@ -129,7 +129,7 @@ def _reminder_handler(self, actor_type_name, actor_id, reminder_name):
ActorRuntime.fire_reminder(actor_type_name, actor_id, reminder_name, req_body)
)
except DaprInternalError as ex:
return wrap_response(500, ex.as_dict())
return wrap_response(500, ex.as_json_safe_dict())
except Exception as ex:
return wrap_response(500, repr(ex), ERROR_CODE_UNKNOWN)

Expand Down
31 changes: 30 additions & 1 deletion tests/clients/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import base64
import json
import unittest

import grpc
Expand All @@ -6,7 +8,7 @@
from google.protobuf.duration_pb2 import Duration

from dapr.clients import DaprGrpcClient
from dapr.clients.exceptions import DaprGrpcError
from dapr.clients.exceptions import DaprGrpcError, DaprInternalError
from dapr.conf import settings

from .fake_dapr_server import FakeDaprSidecar
Expand Down Expand Up @@ -216,3 +218,30 @@ def test_error_code(self):
dapr_error = context.exception

self.assertEqual(dapr_error.error_code(), 'UNKNOWN')

def test_dapr_internal_error_as_json_safe_dict_no_bytes(self):
message = 'Test DaprInternalError.as_json_safe_dict with no raw bytes'
dapr_error = DaprInternalError(message=message)

safe_dict = dapr_error.as_json_safe_dict()
self.assertEqual(safe_dict['message'], message)
self.assertEqual(safe_dict['errorCode'], 'UNKNOWN')
self.assertIsNone(safe_dict['raw_response_bytes'])

# Also check that the safe dict can be serialised to JSON
_ = json.dumps(safe_dict)

def test_dapr_internal_error_as_json_safe_dict_bytes_are_encoded(self):
message = 'Test DaprInternalError.as_json_safe_dict with encoded raw bytes'
raw_bytes = message.encode('utf-8')
dapr_error = DaprInternalError(message=message, raw_response_bytes=raw_bytes)

safe_dict = dapr_error.as_json_safe_dict()
self.assertEqual(safe_dict['message'], message)
self.assertEqual(safe_dict['errorCode'], 'UNKNOWN')

decoded_bytes = base64.b64decode(safe_dict['raw_response_bytes'])
self.assertEqual(decoded_bytes, raw_bytes)

# Also check that the safe dict can be serialised to JSON
_ = json.dumps(safe_dict)

0 comments on commit faebc7a

Please sign in to comment.