Skip to content

🐛 Fixed: Saga Context Serialization and Recovery

Choose a tag to compare

@vadikko2 vadikko2 released this 27 Jan 15:58
· 13 commits to master since this release
69e0c9b

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 COMPLETED in SagaTransaction.__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_failure was expecting TypeError when required fields were missing, but dataclass_wizard actually raises MissingFields exception.
  • Fix: Updated test to expect the correct exception type (MissingFields from dataclass_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 COMPLETED to 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() uses dataclass_wizard.asdict() which converts field names to camelCase (e.g., order_idorderId).
  • 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:

  1. Execute all saga steps
  2. Update context in storage (final update)
  3. Mark saga as COMPLETED in 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 expects MissingFields exception
  • test_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.