pyworkflow-engine 0.2.12__tar.gz → 0.2.14__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 (232) hide show
  1. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/PKG-INFO +1 -1
  2. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyproject.toml +1 -1
  3. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/__init__.py +1 -1
  4. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/tasks.py +38 -4
  5. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/__init__.py +4 -0
  6. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/context.py +73 -0
  7. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/dispatcher.py +11 -2
  8. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/CLAUDE.md +0 -0
  9. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/DISTRIBUTED.md +0 -0
  10. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/LICENSE +0 -0
  11. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/MANIFEST.in +0 -0
  12. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/README.md +0 -0
  13. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/RELEASING.md +0 -0
  14. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/architecture.md +0 -0
  15. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/cancellation.mdx +0 -0
  16. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/continue-as-new.mdx +0 -0
  17. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/events.mdx +0 -0
  18. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/fault-tolerance.mdx +0 -0
  19. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/hooks.mdx +0 -0
  20. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/limitations.mdx +0 -0
  21. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/schedules.mdx +0 -0
  22. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/sleep.mdx +0 -0
  23. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/step-context.mdx +0 -0
  24. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/steps.mdx +0 -0
  25. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/stream-steps.mdx +0 -0
  26. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/stream-workflows.mdx +0 -0
  27. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/concepts/workflows.mdx +0 -0
  28. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/conventions.md +0 -0
  29. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/guides/brokers.mdx +0 -0
  30. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/guides/cli.mdx +0 -0
  31. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/guides/configuration.mdx +0 -0
  32. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/harness-gaps.md +0 -0
  33. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/introduction.mdx +0 -0
  34. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/layers.md +0 -0
  35. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/docs/quickstart.mdx +0 -0
  36. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/__init__.py +0 -0
  37. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/__init__.py +0 -0
  38. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/docker-compose.yml +0 -0
  39. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/pyworkflow.config.yaml +0 -0
  40. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/__init__.py +0 -0
  41. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/basic.py +0 -0
  42. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/batch_processing.py +0 -0
  43. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/cancellation.py +0 -0
  44. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/child_workflow_from_step.py +0 -0
  45. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/child_workflow_patterns.py +0 -0
  46. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/child_workflows.py +0 -0
  47. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/continue_as_new.py +0 -0
  48. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/fault_tolerance.py +0 -0
  49. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/hooks.py +0 -0
  50. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/idempotency.py +0 -0
  51. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/long_running.py +0 -0
  52. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/retries.py +0 -0
  53. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/schedules.py +0 -0
  54. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/sleep_in_step.py +0 -0
  55. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/durable/workflows/step_context.py +0 -0
  56. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/transient/01_basic_workflow.py +0 -0
  57. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/transient/02_fault_tolerance.py +0 -0
  58. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/transient/__init__.py +0 -0
  59. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/celery/transient/pyworkflow.config.yaml +0 -0
  60. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/__init__.py +0 -0
  61. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/01_basic_workflow.py +0 -0
  62. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/02_file_storage.py +0 -0
  63. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/03_retries.py +0 -0
  64. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/04_long_running.py +0 -0
  65. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/05_event_log.py +0 -0
  66. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/06_idempotency.py +0 -0
  67. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/07_hooks.py +0 -0
  68. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/08_cancellation.py +0 -0
  69. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/09_child_workflows.py +0 -0
  70. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/10_child_workflow_patterns.py +0 -0
  71. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/11_continue_as_new.py +0 -0
  72. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/12_schedules.py +0 -0
  73. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/13_step_context.py +0 -0
  74. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/14_child_workflow_from_step.py +0 -0
  75. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/durable/__init__.py +0 -0
  76. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/transient/01_quick_tasks.py +0 -0
  77. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/transient/02_retries.py +0 -0
  78. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/transient/03_sleep.py +0 -0
  79. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/examples/local/transient/__init__.py +0 -0
  80. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/aws/__init__.py +0 -0
  81. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/aws/context.py +0 -0
  82. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/aws/handler.py +0 -0
  83. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/aws/testing.py +0 -0
  84. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/__init__.py +0 -0
  85. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/app.py +0 -0
  86. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/loop.py +0 -0
  87. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/scheduler.py +0 -0
  88. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/celery/singleton.py +0 -0
  89. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/__init__.py +0 -0
  90. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/__main__.py +0 -0
  91. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/__init__.py +0 -0
  92. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/hooks.py +0 -0
  93. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/quickstart.py +0 -0
  94. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/runs.py +0 -0
  95. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/scheduler.py +0 -0
  96. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/schedules.py +0 -0
  97. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/setup.py +0 -0
  98. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/worker.py +0 -0
  99. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/commands/workflows.py +0 -0
  100. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/output/__init__.py +0 -0
  101. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/output/formatters.py +0 -0
  102. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/output/styles.py +0 -0
  103. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/__init__.py +0 -0
  104. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/async_helpers.py +0 -0
  105. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/config.py +0 -0
  106. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/config_generator.py +0 -0
  107. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/discovery.py +0 -0
  108. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/docker_manager.py +0 -0
  109. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/interactive.py +0 -0
  110. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/cli/utils/storage.py +0 -0
  111. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/config.py +0 -0
  112. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/__init__.py +0 -0
  113. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/aws.py +0 -0
  114. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/base.py +0 -0
  115. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/local.py +0 -0
  116. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/mock.py +0 -0
  117. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/context/step_context.py +0 -0
  118. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/__init__.py +0 -0
  119. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/exceptions.py +0 -0
  120. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/registry.py +0 -0
  121. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/scheduled.py +0 -0
  122. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/step.py +0 -0
  123. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/validation.py +0 -0
  124. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/core/workflow.py +0 -0
  125. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/discovery.py +0 -0
  126. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/engine/__init__.py +0 -0
  127. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/engine/events.py +0 -0
  128. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/engine/executor.py +0 -0
  129. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/engine/replay.py +0 -0
  130. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/observability/__init__.py +0 -0
  131. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/observability/logging.py +0 -0
  132. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/__init__.py +0 -0
  133. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/child_handle.py +0 -0
  134. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/child_workflow.py +0 -0
  135. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/continue_as_new.py +0 -0
  136. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/define_hook.py +0 -0
  137. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/hooks.py +0 -0
  138. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/resume_hook.py +0 -0
  139. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/schedule.py +0 -0
  140. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/shield.py +0 -0
  141. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/sleep.py +0 -0
  142. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/step_checkpoint.py +0 -0
  143. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/primitives/step_hook.py +0 -0
  144. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/runtime/__init__.py +0 -0
  145. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/runtime/base.py +0 -0
  146. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/runtime/celery.py +0 -0
  147. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/runtime/factory.py +0 -0
  148. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/runtime/local.py +0 -0
  149. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/scheduler/__init__.py +0 -0
  150. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/scheduler/local.py +0 -0
  151. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/serialization/__init__.py +0 -0
  152. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/serialization/decoder.py +0 -0
  153. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/serialization/encoder.py +0 -0
  154. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/__init__.py +0 -0
  155. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/base.py +0 -0
  156. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/cassandra.py +0 -0
  157. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/citus.py +0 -0
  158. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/config.py +0 -0
  159. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/dynamodb.py +0 -0
  160. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/file.py +0 -0
  161. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/memory.py +0 -0
  162. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/migrations/__init__.py +0 -0
  163. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/migrations/base.py +0 -0
  164. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/mysql.py +0 -0
  165. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/postgres.py +0 -0
  166. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/schemas.py +0 -0
  167. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/storage/sqlite.py +0 -0
  168. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/checkpoint.py +0 -0
  169. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/consumer.py +0 -0
  170. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/decorator.py +0 -0
  171. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/emit.py +0 -0
  172. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/registry.py +0 -0
  173. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/runtime.py +0 -0
  174. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/signal.py +0 -0
  175. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/streams/step_context.py +0 -0
  176. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/utils/__init__.py +0 -0
  177. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/utils/duration.py +0 -0
  178. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/utils/helpers.py +0 -0
  179. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow/utils/schedule.py +0 -0
  180. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/pyworkflow_engine.egg-info/SOURCES.txt +0 -0
  181. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/setup.cfg +0 -0
  182. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/__init__.py +0 -0
  183. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_cancellation.py +0 -0
  184. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_cassandra_storage.py +0 -0
  185. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_child_workflows.py +0 -0
  186. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_continue_as_new.py +0 -0
  187. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_dynamodb_storage.py +0 -0
  188. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_fault_tolerance.py +0 -0
  189. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_schedule_storage.py +0 -0
  190. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_schema_migrations.py +0 -0
  191. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_singleton.py +0 -0
  192. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_stream_e2e.py +0 -0
  193. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/integration/test_workflow_suspended.py +0 -0
  194. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/__init__.py +0 -0
  195. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/__init__.py +0 -0
  196. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/test_cassandra_storage.py +0 -0
  197. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/test_citus_storage.py +0 -0
  198. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/test_dynamodb_storage.py +0 -0
  199. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/test_postgres_storage.py +0 -0
  200. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/backends/test_sqlite_storage.py +0 -0
  201. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/conftest.py +0 -0
  202. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/storage/__init__.py +0 -0
  203. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/storage/test_migrations.py +0 -0
  204. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_cancellation.py +0 -0
  205. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_child_workflows.py +0 -0
  206. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_cli_worker.py +0 -0
  207. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_continue_as_new.py +0 -0
  208. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_emit.py +0 -0
  209. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_event_limits.py +0 -0
  210. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_executor.py +0 -0
  211. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_fault_tolerance.py +0 -0
  212. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_force_local.py +0 -0
  213. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_hooks.py +0 -0
  214. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_parent_run_id.py +0 -0
  215. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_primitives_from_steps.py +0 -0
  216. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_registry.py +0 -0
  217. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_replay.py +0 -0
  218. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_retention.py +0 -0
  219. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_schedule_schemas.py +0 -0
  220. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_schedule_utils.py +0 -0
  221. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_scheduled_workflow.py +0 -0
  222. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_signal.py +0 -0
  223. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_singleton.py +0 -0
  224. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_step.py +0 -0
  225. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_step_checkpoint.py +0 -0
  226. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_step_context.py +0 -0
  227. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_step_hook.py +0 -0
  228. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_stream_storage.py +0 -0
  229. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_stream_workflow.py +0 -0
  230. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_validation.py +0 -0
  231. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_workflow.py +0 -0
  232. {pyworkflow_engine-0.2.12 → pyworkflow_engine-0.2.14}/tests/unit/test_workflow_suspended.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyworkflow-engine
3
- Version: 0.2.12
3
+ Version: 0.2.14
4
4
  Summary: A Python implementation of durable, event-sourced workflows inspired by Vercel Workflow
5
5
  Author: PyWorkflow Contributors
6
6
  License: MIT
@@ -7,7 +7,7 @@ packages = [{include = "pyworkflow"}]
7
7
 
8
8
  [project]
9
9
  name = "pyworkflow-engine"
10
- version = "0.2.12"
10
+ version = "0.2.14"
11
11
  description = "A Python implementation of durable, event-sourced workflows inspired by Vercel Workflow"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -29,7 +29,7 @@ Quick Start:
29
29
  >>> run_id = await start(my_workflow, "Alice")
30
30
  """
31
31
 
32
- __version__ = "0.2.12"
32
+ __version__ = "0.2.14"
33
33
 
34
34
  # Configuration
35
35
  from pyworkflow.config import (
@@ -508,8 +508,17 @@ async def _record_step_completion_and_resume(
508
508
  run_id, EventType.STEP_COMPLETED.value, step_id=step_id
509
509
  )
510
510
  if already_completed:
511
+ # A prior worker recorded STEP_COMPLETED but may have crashed before
512
+ # scheduling the workflow resume. Re-schedule defensively — the resume
513
+ # task is idempotent via try_claim_run(SUSPENDED -> RUNNING).
514
+ schedule_workflow_resumption(
515
+ run_id,
516
+ datetime.now(UTC),
517
+ storage_config,
518
+ triggered_by="step_completed_idempotent_retry",
519
+ )
511
520
  logger.info(
512
- "Step already completed by another task, skipping",
521
+ "Step already completed by another task, re-scheduled resume",
513
522
  run_id=run_id,
514
523
  step_id=step_id,
515
524
  step_name=step_name,
@@ -537,8 +546,16 @@ async def _record_step_completion_and_resume(
537
546
  run_id, EventType.STEP_COMPLETED.value, step_id=step_id
538
547
  )
539
548
  if already_completed:
549
+ # Defensive re-schedule: the peer that recorded STEP_COMPLETED may
550
+ # have crashed before scheduling resume. Safe due to try_claim_run.
551
+ schedule_workflow_resumption(
552
+ run_id,
553
+ datetime.now(UTC),
554
+ storage_config,
555
+ triggered_by="step_completed_idempotent_retry",
556
+ )
540
557
  logger.info(
541
- "Step already completed by another task during wait, skipping",
558
+ "Step already completed by another task during wait, re-scheduled resume",
542
559
  run_id=run_id,
543
560
  step_id=step_id,
544
561
  step_name=step_name,
@@ -676,8 +693,17 @@ async def _record_step_failure_and_resume(
676
693
  run_id, EventType.STEP_FAILED.value, step_id=step_id, is_retryable="False"
677
694
  )
678
695
  if already_completed or already_failed_terminal:
696
+ # A prior worker recorded the terminal event but may have crashed before
697
+ # scheduling the workflow resume. Re-schedule defensively — safe due to
698
+ # try_claim_run(SUSPENDED -> RUNNING) idempotency.
699
+ schedule_workflow_resumption(
700
+ run_id,
701
+ datetime.now(UTC),
702
+ storage_config,
703
+ triggered_by="step_failed_idempotent_retry",
704
+ )
679
705
  logger.info(
680
- "Step already completed/failed by another task, skipping",
706
+ "Step already completed/failed by another task, re-scheduled resume",
681
707
  run_id=run_id,
682
708
  step_id=step_id,
683
709
  step_name=step_name,
@@ -708,8 +734,16 @@ async def _record_step_failure_and_resume(
708
734
  run_id, EventType.STEP_FAILED.value, step_id=step_id, is_retryable="False"
709
735
  )
710
736
  if already_completed or already_failed_terminal:
737
+ # Defensive re-schedule: peer that recorded the terminal event may
738
+ # have crashed before scheduling resume. Safe due to try_claim_run.
739
+ schedule_workflow_resumption(
740
+ run_id,
741
+ datetime.now(UTC),
742
+ storage_config,
743
+ triggered_by="step_failed_idempotent_retry",
744
+ )
711
745
  logger.info(
712
- "Step already completed/failed by another task during wait, skipping",
746
+ "Step already completed/failed by another task during wait, re-scheduled resume",
713
747
  run_id=run_id,
714
748
  step_id=step_id,
715
749
  step_name=step_name,
@@ -28,8 +28,10 @@ from pyworkflow.streams.checkpoint import ( # noqa: F401
28
28
  )
29
29
  from pyworkflow.streams.consumer import StreamConsumer, poll_once # noqa: F401
30
30
  from pyworkflow.streams.context import ( # noqa: F401
31
+ acknowledge_inbox_signal,
31
32
  get_checkpoint,
32
33
  get_current_signal,
34
+ poll_inbox,
33
35
  save_checkpoint,
34
36
  set_result,
35
37
  suspend,
@@ -73,6 +75,8 @@ __all__ = [
73
75
  "get_current_signal",
74
76
  "get_checkpoint",
75
77
  "save_checkpoint",
78
+ "poll_inbox",
79
+ "acknowledge_inbox_signal",
76
80
  # Checkpoint
77
81
  "CheckpointBackend",
78
82
  "DefaultCheckpointBackend",
@@ -182,3 +182,76 @@ def set_stream_run_id(stream_run_id: str | None) -> Any:
182
182
  Returns a token that can be used to reset the value.
183
183
  """
184
184
  return _current_stream_run_id.set(stream_run_id)
185
+
186
+
187
+ async def poll_inbox(
188
+ signal_types: list[str] | None = None,
189
+ ) -> list[Signal]:
190
+ """Get unacknowledged signals for the current running stream step.
191
+
192
+ Allows a step that is in ``running`` status to discover signals that
193
+ arrived while it was executing. Uses the same storage query as the
194
+ post-execution drain mechanism (``get_pending_signals``) but can be
195
+ called from *within* the lifecycle function, so a long-running step
196
+ does not have to return first.
197
+
198
+ Signals are filtered to the current ``stream_run_id`` to prevent
199
+ cross-run leakage.
200
+
201
+ Args:
202
+ signal_types: Optional whitelist. When provided, only signals
203
+ whose ``signal_type`` is in this list are returned.
204
+
205
+ Returns:
206
+ A list of :class:`Signal` objects ordered by sequence number.
207
+ """
208
+ from loguru import logger
209
+
210
+ storage = _current_storage.get()
211
+ stream_id = _current_stream_id.get()
212
+ step_run_id = _current_step_run_id.get()
213
+ stream_run_id = _current_stream_run_id.get()
214
+
215
+ if not storage or not stream_id or not step_run_id:
216
+ return []
217
+
218
+ try:
219
+ pending = await storage.get_pending_signals(stream_id, step_run_id)
220
+ except Exception:
221
+ logger.debug("[poll_inbox] get_pending_signals failed", exc_info=True)
222
+ return []
223
+
224
+ results: list[Signal] = []
225
+ for row in pending:
226
+ # Filter to current stream run
227
+ if stream_run_id and row.get("stream_run_id") != stream_run_id:
228
+ continue
229
+ # Optional signal type filter
230
+ if signal_types and row.get("signal_type") not in signal_types:
231
+ continue
232
+ results.append(
233
+ Signal(
234
+ signal_id=row["signal_id"],
235
+ stream_id=row["stream_id"],
236
+ signal_type=row["signal_type"],
237
+ payload=row.get("payload") or {},
238
+ sequence=row.get("sequence", 0),
239
+ source_run_id=row.get("source_run_id"),
240
+ stream_run_id=row.get("stream_run_id"),
241
+ metadata=row.get("metadata") or {},
242
+ )
243
+ )
244
+ return results
245
+
246
+
247
+ async def acknowledge_inbox_signal(signal_id: str) -> None:
248
+ """Acknowledge a signal retrieved via :func:`poll_inbox`.
249
+
250
+ Once acknowledged the signal will not appear in subsequent
251
+ ``poll_inbox`` calls or in the post-execution drain, preventing
252
+ double processing.
253
+ """
254
+ storage = _current_storage.get()
255
+ step_run_id = _current_step_run_id.get()
256
+ if storage and step_run_id:
257
+ await storage.acknowledge_signal(signal_id, step_run_id)
@@ -66,9 +66,18 @@ async def dispatch_signal(signal: Signal, storage: Any) -> None:
66
66
  )
67
67
 
68
68
  if not waiting_steps:
69
- logger.warning(
69
+ # Determine whether any subscriptions are in "running" status.
70
+ # If so the signal is safely persisted in the signals table and
71
+ # will be picked up by poll_inbox() (called from within the
72
+ # running step) or by _drain_pending_signals_for_step() when the
73
+ # step transitions back to "waiting". Use DEBUG to avoid noisy
74
+ # warnings for this expected scenario.
75
+ has_running = any(s.get("status") == "running" for s in (all_subs or []))
76
+ log_fn = logger.debug if has_running else logger.warning
77
+ log_fn(
70
78
  f"No waiting steps for {signal.signal_type} on {signal.stream_id} "
71
- f"(stream_run_id={signal.stream_run_id})",
79
+ f"(stream_run_id={signal.stream_run_id})"
80
+ + (" — signal queued for running step inbox" if has_running else ""),
72
81
  stream_id=signal.stream_id,
73
82
  signal_type=signal.signal_type,
74
83
  stream_run_id=signal.stream_run_id,