fix: ensure Decimal values in metadata are JSON serializable (fixes #19936) (#19955)

Co-authored-by: crazywoola <427733928@qq.com>
This commit is contained in:
Zihe JI 2025-05-20 15:38:31 +08:00 committed by GitHub
parent 8cb3b4aef2
commit 87f9d11d65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 8 additions and 3 deletions

View File

@ -11,6 +11,7 @@ from sqlalchemy import UnaryExpression, asc, delete, desc, select
from sqlalchemy.engine import Engine from sqlalchemy.engine import Engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from core.model_runtime.utils.encoders import jsonable_encoder
from core.workflow.entities.node_entities import NodeRunMetadataKey from core.workflow.entities.node_entities import NodeRunMetadataKey
from core.workflow.entities.node_execution_entities import ( from core.workflow.entities.node_execution_entities import (
NodeExecution, NodeExecution,
@ -171,7 +172,9 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository)
db_model.status = domain_model.status db_model.status = domain_model.status
db_model.error = domain_model.error db_model.error = domain_model.error
db_model.elapsed_time = domain_model.elapsed_time db_model.elapsed_time = domain_model.elapsed_time
db_model.execution_metadata = json.dumps(domain_model.metadata) if domain_model.metadata else None db_model.execution_metadata = (
json.dumps(jsonable_encoder(domain_model.metadata)) if domain_model.metadata else None
)
db_model.created_at = domain_model.created_at db_model.created_at = domain_model.created_at
db_model.created_by_role = self._creator_user_role db_model.created_by_role = self._creator_user_role
db_model.created_by = self._creator_user_id db_model.created_by = self._creator_user_id

View File

@ -4,12 +4,14 @@ Unit tests for the SQLAlchemy implementation of WorkflowNodeExecutionRepository.
import json import json
from datetime import datetime from datetime import datetime
from decimal import Decimal
from unittest.mock import MagicMock, PropertyMock from unittest.mock import MagicMock, PropertyMock
import pytest import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.orm import Session, sessionmaker
from core.model_runtime.utils.encoders import jsonable_encoder
from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository
from core.workflow.entities.node_entities import NodeRunMetadataKey from core.workflow.entities.node_entities import NodeRunMetadataKey
from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus
@ -298,7 +300,7 @@ def test_to_db_model(repository):
status=NodeExecutionStatus.RUNNING, status=NodeExecutionStatus.RUNNING,
error=None, error=None,
elapsed_time=1.5, elapsed_time=1.5,
metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100}, metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100, NodeRunMetadataKey.TOTAL_PRICE: Decimal("0.0")},
created_at=datetime.now(), created_at=datetime.now(),
finished_at=None, finished_at=None,
) )
@ -324,7 +326,7 @@ def test_to_db_model(repository):
assert db_model.inputs_dict == domain_model.inputs assert db_model.inputs_dict == domain_model.inputs
assert db_model.process_data_dict == domain_model.process_data assert db_model.process_data_dict == domain_model.process_data
assert db_model.outputs_dict == domain_model.outputs assert db_model.outputs_dict == domain_model.outputs
assert db_model.execution_metadata_dict == domain_model.metadata assert db_model.execution_metadata_dict == jsonable_encoder(domain_model.metadata)
assert db_model.status == domain_model.status assert db_model.status == domain_model.status
assert db_model.error == domain_model.error assert db_model.error == domain_model.error