python-cqrs 4.7.0__tar.gz → 4.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {python_cqrs-4.7.0/src/python_cqrs.egg-info → python_cqrs-4.7.1}/PKG-INFO +1 -1
  2. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/pyproject.toml +1 -1
  3. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/compensation.py +8 -0
  4. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/saga.py +8 -0
  5. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/memory.py +1 -1
  6. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/protocol.py +4 -3
  7. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/sqlalchemy.py +0 -1
  8. {python_cqrs-4.7.0 → python_cqrs-4.7.1/src/python_cqrs.egg-info}/PKG-INFO +1 -1
  9. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/LICENSE +0 -0
  10. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/README.md +0 -0
  11. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/setup.cfg +0 -0
  12. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/__init__.py +0 -0
  13. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/adapters/__init__.py +0 -0
  14. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/adapters/amqp.py +0 -0
  15. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/adapters/circuit_breaker.py +0 -0
  16. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/adapters/kafka.py +0 -0
  17. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/adapters/protocol.py +0 -0
  18. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/compressors/__init__.py +0 -0
  19. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/compressors/protocol.py +0 -0
  20. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/compressors/zlib.py +0 -0
  21. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/container/__init__.py +0 -0
  22. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/container/dependency_injector.py +0 -0
  23. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/container/di.py +0 -0
  24. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/container/protocol.py +0 -0
  25. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/deserializers/__init__.py +0 -0
  26. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/deserializers/exceptions.py +0 -0
  27. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/deserializers/json.py +0 -0
  28. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/__init__.py +0 -0
  29. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/event.py +0 -0
  30. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/exceptions.py +0 -0
  31. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/models.py +0 -0
  32. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/request.py +0 -0
  33. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/saga.py +0 -0
  34. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/dispatcher/streaming.py +0 -0
  35. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/__init__.py +0 -0
  36. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/bootstrap.py +0 -0
  37. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/event.py +0 -0
  38. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/event_emitter.py +0 -0
  39. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/event_handler.py +0 -0
  40. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/event_processor.py +0 -0
  41. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/events/map.py +0 -0
  42. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/mediator.py +0 -0
  43. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/message_brokers/__init__.py +0 -0
  44. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/message_brokers/amqp.py +0 -0
  45. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/message_brokers/devnull.py +0 -0
  46. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/message_brokers/kafka.py +0 -0
  47. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/message_brokers/protocol.py +0 -0
  48. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/middlewares/__init__.py +0 -0
  49. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/middlewares/base.py +0 -0
  50. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/middlewares/logging.py +0 -0
  51. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/outbox/__init__.py +0 -0
  52. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/outbox/map.py +0 -0
  53. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/outbox/mock.py +0 -0
  54. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/outbox/repository.py +0 -0
  55. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/outbox/sqlalchemy.py +0 -0
  56. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/producer.py +0 -0
  57. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/__init__.py +0 -0
  58. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/bootstrap.py +0 -0
  59. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/cor_request_handler.py +0 -0
  60. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/map.py +0 -0
  61. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/mermaid.py +0 -0
  62. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/request.py +0 -0
  63. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/requests/request_handler.py +0 -0
  64. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/response.py +0 -0
  65. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/__init__.py +0 -0
  66. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/bootstrap.py +0 -0
  67. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/circuit_breaker.py +0 -0
  68. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/execution.py +0 -0
  69. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/fallback.py +0 -0
  70. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/mermaid.py +0 -0
  71. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/models.py +0 -0
  72. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/recovery.py +0 -0
  73. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/step.py +0 -0
  74. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/__init__.py +0 -0
  75. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/enums.py +0 -0
  76. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/storage/models.py +0 -0
  77. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/saga/validation.py +0 -0
  78. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/serializers/__init__.py +0 -0
  79. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/serializers/default.py +0 -0
  80. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/cqrs/types.py +0 -0
  81. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/python_cqrs.egg-info/SOURCES.txt +0 -0
  82. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/python_cqrs.egg-info/dependency_links.txt +0 -0
  83. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/python_cqrs.egg-info/requires.txt +0 -0
  84. {python_cqrs-4.7.0 → python_cqrs-4.7.1}/src/python_cqrs.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cqrs
3
- Version: 4.7.0
3
+ Version: 4.7.1
4
4
  Summary: Python CQRS pattern implementation
5
5
  Author-email: Vadim Kozyrevskiy <vadikko2@mail.ru>, Dmitry Kutlubaev <kutlubaev00@mail.ru>
6
6
  Maintainer-email: Vadim Kozyrevskiy <vadikko2@mail.ru>
@@ -31,7 +31,7 @@ maintainers = [{name = "Vadim Kozyrevskiy", email = "vadikko2@mail.ru"}]
31
31
  name = "python-cqrs"
32
32
  readme = "README.md"
33
33
  requires-python = ">=3.10"
34
- version = "4.7.0"
34
+ version = "4.7.1"
35
35
 
36
36
  [project.optional-dependencies]
37
37
  aiobreaker = ["aiobreaker>=0.3.0"]
@@ -54,6 +54,14 @@ class SagaCompensator(typing.Generic[ContextT]):
54
54
  """
55
55
  await self._storage.update_status(self._saga_id, SagaStatus.COMPENSATING)
56
56
 
57
+ if not completed_steps:
58
+ logger.info(
59
+ f"Saga {self._saga_id}: completed_steps is empty, "
60
+ "skipping compensation (no step.compensate() will be called).",
61
+ )
62
+ await self._storage.update_status(self._saga_id, SagaStatus.FAILED)
63
+ return
64
+
57
65
  # Load history to skip already compensated steps
58
66
  history = await self._storage.get_step_history(self._saga_id)
59
67
  compensated_steps = {
@@ -234,6 +234,14 @@ class SagaTransaction(typing.Generic[ContextT]):
234
234
  for step in reconstructed_steps
235
235
  ]
236
236
 
237
+ if not self._completed_steps:
238
+ logger.warning(
239
+ f"Saga {self._saga_id}: no completed steps to compensate "
240
+ "(saga failed before any step finished 'act', or step names in "
241
+ "storage do not match saga step class names). "
242
+ "Marking as FAILED without calling compensate().",
243
+ )
244
+
237
245
  # Immediately proceed to compensation - no forward execution
238
246
  await self._compensate()
239
247
 
@@ -123,7 +123,7 @@ class MemorySagaStorage(ISagaStorage):
123
123
  max_recovery_attempts: int = 5,
124
124
  stale_after_seconds: int | None = None,
125
125
  ) -> list[uuid.UUID]:
126
- recoverable = (SagaStatus.RUNNING, SagaStatus.COMPENSATING, SagaStatus.FAILED)
126
+ recoverable = (SagaStatus.RUNNING, SagaStatus.COMPENSATING)
127
127
  now = datetime.datetime.now(datetime.timezone.utc)
128
128
  threshold = (
129
129
  (now - datetime.timedelta(seconds=stale_after_seconds))
@@ -90,9 +90,10 @@ class ISagaStorage(abc.ABC):
90
90
  updated). None means no staleness filter (backward compatible).
91
91
 
92
92
  Returns:
93
- List of saga IDs (RUNNING, COMPENSATING, or FAILED), ordered by
94
- updated_at ascending, with recovery_attempts < max_recovery_attempts,
95
- and optionally updated_at older than the staleness threshold.
93
+ List of saga IDs (RUNNING or COMPENSATING only; FAILED sagas are
94
+ not included), ordered by updated_at ascending, with
95
+ recovery_attempts < max_recovery_attempts, and optionally
96
+ updated_at older than the staleness threshold.
96
97
  """
97
98
 
98
99
  @abc.abstractmethod
@@ -321,7 +321,6 @@ class SqlAlchemySagaStorage(ISagaStorage):
321
321
  recoverable = (
322
322
  SagaStatus.RUNNING,
323
323
  SagaStatus.COMPENSATING,
324
- SagaStatus.FAILED,
325
324
  )
326
325
  async with self.session_factory() as session:
327
326
  stmt = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cqrs
3
- Version: 4.7.0
3
+ Version: 4.7.1
4
4
  Summary: Python CQRS pattern implementation
5
5
  Author-email: Vadim Kozyrevskiy <vadikko2@mail.ru>, Dmitry Kutlubaev <kutlubaev00@mail.ru>
6
6
  Maintainer-email: Vadim Kozyrevskiy <vadikko2@mail.ru>
File without changes
File without changes
File without changes