🐛 Fixed: Saga Context Serialization and Recovery
Bug Fixes
Saga Context Serialization and Recovery
Fixed context not being saved to storage after saga completion
- Issue: When a saga completed successfully, the context was not being persisted to storage before marking the saga as
COMPLETED. This could lead to data loss if the context was modified during the last step execution. - Fix: Added final context update before setting saga status to
COMPLETEDinSagaTransaction.__aiter__(). - Impact: Saga context is now properly persisted to storage after all steps complete successfully, ensuring data consistency.
Improved field filtering in SagaContext.from_dict()
- Issue: When deserializing context from dictionary, unknown fields in the input data could cause issues or unexpected behavior.
- Fix: Added field filtering in
SagaContext.from_dict()to only include known dataclass fields before deserialization. - Impact: More robust context reconstruction that ignores unknown fields, preventing potential errors during saga recovery.
Test Improvements
Fixed test expectation for context reconstruction failures
- Issue: Test
test_recover_saga_raises_on_context_reconstruction_failurewas expectingTypeErrorwhen required fields were missing, butdataclass_wizardactually raisesMissingFieldsexception. - Fix: Updated test to expect the correct exception type (
MissingFieldsfromdataclass_wizard.errors). - Impact: Tests now correctly validate error handling during context reconstruction.
Changes
cqrs.saga.saga.SagaTransaction
- Added final context update before marking saga as
COMPLETEDto ensure context persistence.
cqrs.saga.models.SagaContext
- Enhanced
from_dict()method to filter input data to only include known dataclass fields, improving robustness during deserialization.
Technical Details
Context Serialization
SagaContext.to_dict()usesdataclass_wizard.asdict()which converts field names to camelCase (e.g.,order_id→orderId).SagaContext.from_dict()now filters input data to only include fields that exist in the dataclass definition before deserialization.
Saga Completion Flow
The saga completion process now follows this sequence:
- Execute all saga steps
- Update context in storage (final update)
- Mark saga as
COMPLETEDin storage
This ensures that any context modifications made during the last step are properly persisted.
Testing
All existing tests pass, including:
test_recover_saga_raises_on_context_reconstruction_failure- now correctly expectsMissingFieldsexceptiontest_recover_saga_updates_context_during_recovery- validates context persistence after recovery- All other saga recovery and execution tests (85 tests total)
Migration Notes
No breaking changes. This is a bug fix release that improves data consistency and error handling.
If you're using SagaContext.from_dict() with data containing unknown fields, those fields will now be automatically filtered out. This should not affect normal usage but may change behavior if you were relying on unknown fields being passed through.