pyworkflow-engine 0.2.0b1__tar.gz → 0.2.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 (229) hide show
  1. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/PKG-INFO +1 -1
  2. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyproject.toml +1 -1
  3. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/__init__.py +1 -1
  4. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/tasks.py +97 -15
  5. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/CLAUDE.md +0 -0
  6. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/DISTRIBUTED.md +0 -0
  7. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/LICENSE +0 -0
  8. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/MANIFEST.in +0 -0
  9. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/README.md +0 -0
  10. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/RELEASING.md +0 -0
  11. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/architecture.md +0 -0
  12. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/cancellation.mdx +0 -0
  13. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/continue-as-new.mdx +0 -0
  14. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/events.mdx +0 -0
  15. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/fault-tolerance.mdx +0 -0
  16. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/hooks.mdx +0 -0
  17. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/limitations.mdx +0 -0
  18. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/schedules.mdx +0 -0
  19. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/sleep.mdx +0 -0
  20. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/step-context.mdx +0 -0
  21. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/steps.mdx +0 -0
  22. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/concepts/workflows.mdx +0 -0
  23. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/conventions.md +0 -0
  24. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/guides/brokers.mdx +0 -0
  25. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/guides/cli.mdx +0 -0
  26. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/guides/configuration.mdx +0 -0
  27. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/harness-gaps.md +0 -0
  28. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/introduction.mdx +0 -0
  29. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/layers.md +0 -0
  30. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/docs/quickstart.mdx +0 -0
  31. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/__init__.py +0 -0
  32. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/__init__.py +0 -0
  33. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/docker-compose.yml +0 -0
  34. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/pyworkflow.config.yaml +0 -0
  35. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/__init__.py +0 -0
  36. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/basic.py +0 -0
  37. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/batch_processing.py +0 -0
  38. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/cancellation.py +0 -0
  39. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/child_workflow_from_step.py +0 -0
  40. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/child_workflow_patterns.py +0 -0
  41. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/child_workflows.py +0 -0
  42. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/continue_as_new.py +0 -0
  43. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/fault_tolerance.py +0 -0
  44. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/hooks.py +0 -0
  45. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/idempotency.py +0 -0
  46. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/long_running.py +0 -0
  47. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/retries.py +0 -0
  48. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/schedules.py +0 -0
  49. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/sleep_in_step.py +0 -0
  50. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/durable/workflows/step_context.py +0 -0
  51. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/transient/01_basic_workflow.py +0 -0
  52. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/transient/02_fault_tolerance.py +0 -0
  53. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/transient/__init__.py +0 -0
  54. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/celery/transient/pyworkflow.config.yaml +0 -0
  55. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/__init__.py +0 -0
  56. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/01_basic_workflow.py +0 -0
  57. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/02_file_storage.py +0 -0
  58. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/03_retries.py +0 -0
  59. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/04_long_running.py +0 -0
  60. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/05_event_log.py +0 -0
  61. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/06_idempotency.py +0 -0
  62. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/07_hooks.py +0 -0
  63. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/08_cancellation.py +0 -0
  64. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/09_child_workflows.py +0 -0
  65. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/10_child_workflow_patterns.py +0 -0
  66. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/11_continue_as_new.py +0 -0
  67. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/12_schedules.py +0 -0
  68. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/13_step_context.py +0 -0
  69. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/14_child_workflow_from_step.py +0 -0
  70. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/durable/__init__.py +0 -0
  71. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/transient/01_quick_tasks.py +0 -0
  72. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/transient/02_retries.py +0 -0
  73. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/transient/03_sleep.py +0 -0
  74. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/examples/local/transient/__init__.py +0 -0
  75. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/aws/__init__.py +0 -0
  76. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/aws/context.py +0 -0
  77. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/aws/handler.py +0 -0
  78. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/aws/testing.py +0 -0
  79. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/__init__.py +0 -0
  80. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/app.py +0 -0
  81. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/loop.py +0 -0
  82. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/scheduler.py +0 -0
  83. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/celery/singleton.py +0 -0
  84. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/__init__.py +0 -0
  85. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/__main__.py +0 -0
  86. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/__init__.py +0 -0
  87. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/hooks.py +0 -0
  88. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/quickstart.py +0 -0
  89. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/runs.py +0 -0
  90. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/scheduler.py +0 -0
  91. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/schedules.py +0 -0
  92. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/setup.py +0 -0
  93. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/worker.py +0 -0
  94. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/commands/workflows.py +0 -0
  95. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/output/__init__.py +0 -0
  96. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/output/formatters.py +0 -0
  97. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/output/styles.py +0 -0
  98. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/__init__.py +0 -0
  99. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/async_helpers.py +0 -0
  100. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/config.py +0 -0
  101. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/config_generator.py +0 -0
  102. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/discovery.py +0 -0
  103. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/docker_manager.py +0 -0
  104. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/interactive.py +0 -0
  105. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/cli/utils/storage.py +0 -0
  106. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/config.py +0 -0
  107. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/__init__.py +0 -0
  108. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/aws.py +0 -0
  109. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/base.py +0 -0
  110. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/local.py +0 -0
  111. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/mock.py +0 -0
  112. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/context/step_context.py +0 -0
  113. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/__init__.py +0 -0
  114. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/exceptions.py +0 -0
  115. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/registry.py +0 -0
  116. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/scheduled.py +0 -0
  117. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/step.py +0 -0
  118. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/validation.py +0 -0
  119. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/core/workflow.py +0 -0
  120. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/discovery.py +0 -0
  121. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/engine/__init__.py +0 -0
  122. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/engine/events.py +0 -0
  123. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/engine/executor.py +0 -0
  124. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/engine/replay.py +0 -0
  125. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/observability/__init__.py +0 -0
  126. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/observability/logging.py +0 -0
  127. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/__init__.py +0 -0
  128. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/child_handle.py +0 -0
  129. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/child_workflow.py +0 -0
  130. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/continue_as_new.py +0 -0
  131. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/define_hook.py +0 -0
  132. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/hooks.py +0 -0
  133. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/resume_hook.py +0 -0
  134. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/schedule.py +0 -0
  135. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/shield.py +0 -0
  136. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/sleep.py +0 -0
  137. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/step_checkpoint.py +0 -0
  138. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/primitives/step_hook.py +0 -0
  139. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/runtime/__init__.py +0 -0
  140. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/runtime/base.py +0 -0
  141. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/runtime/celery.py +0 -0
  142. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/runtime/factory.py +0 -0
  143. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/runtime/local.py +0 -0
  144. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/scheduler/__init__.py +0 -0
  145. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/scheduler/local.py +0 -0
  146. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/serialization/__init__.py +0 -0
  147. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/serialization/decoder.py +0 -0
  148. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/serialization/encoder.py +0 -0
  149. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/__init__.py +0 -0
  150. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/base.py +0 -0
  151. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/cassandra.py +0 -0
  152. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/citus.py +0 -0
  153. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/config.py +0 -0
  154. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/dynamodb.py +0 -0
  155. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/file.py +0 -0
  156. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/memory.py +0 -0
  157. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/migrations/__init__.py +0 -0
  158. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/migrations/base.py +0 -0
  159. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/mysql.py +0 -0
  160. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/postgres.py +0 -0
  161. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/schemas.py +0 -0
  162. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/storage/sqlite.py +0 -0
  163. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/__init__.py +0 -0
  164. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/checkpoint.py +0 -0
  165. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/consumer.py +0 -0
  166. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/context.py +0 -0
  167. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/decorator.py +0 -0
  168. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/dispatcher.py +0 -0
  169. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/emit.py +0 -0
  170. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/registry.py +0 -0
  171. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/signal.py +0 -0
  172. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/streams/step_context.py +0 -0
  173. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/utils/__init__.py +0 -0
  174. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/utils/duration.py +0 -0
  175. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/utils/helpers.py +0 -0
  176. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow/utils/schedule.py +0 -0
  177. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/pyworkflow_engine.egg-info/SOURCES.txt +0 -0
  178. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/setup.cfg +0 -0
  179. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/__init__.py +0 -0
  180. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_cancellation.py +0 -0
  181. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_cassandra_storage.py +0 -0
  182. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_child_workflows.py +0 -0
  183. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_continue_as_new.py +0 -0
  184. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_dynamodb_storage.py +0 -0
  185. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_fault_tolerance.py +0 -0
  186. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_schedule_storage.py +0 -0
  187. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_schema_migrations.py +0 -0
  188. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_singleton.py +0 -0
  189. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_stream_e2e.py +0 -0
  190. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/integration/test_workflow_suspended.py +0 -0
  191. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/__init__.py +0 -0
  192. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/__init__.py +0 -0
  193. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/test_cassandra_storage.py +0 -0
  194. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/test_citus_storage.py +0 -0
  195. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/test_dynamodb_storage.py +0 -0
  196. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/test_postgres_storage.py +0 -0
  197. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/backends/test_sqlite_storage.py +0 -0
  198. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/conftest.py +0 -0
  199. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/storage/__init__.py +0 -0
  200. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/storage/test_migrations.py +0 -0
  201. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_cancellation.py +0 -0
  202. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_child_workflows.py +0 -0
  203. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_cli_worker.py +0 -0
  204. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_continue_as_new.py +0 -0
  205. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_emit.py +0 -0
  206. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_event_limits.py +0 -0
  207. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_executor.py +0 -0
  208. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_fault_tolerance.py +0 -0
  209. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_force_local.py +0 -0
  210. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_hooks.py +0 -0
  211. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_parent_run_id.py +0 -0
  212. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_primitives_from_steps.py +0 -0
  213. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_registry.py +0 -0
  214. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_replay.py +0 -0
  215. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_retention.py +0 -0
  216. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_schedule_schemas.py +0 -0
  217. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_schedule_utils.py +0 -0
  218. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_scheduled_workflow.py +0 -0
  219. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_signal.py +0 -0
  220. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_singleton.py +0 -0
  221. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_step.py +0 -0
  222. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_step_checkpoint.py +0 -0
  223. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_step_context.py +0 -0
  224. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_step_hook.py +0 -0
  225. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_stream_storage.py +0 -0
  226. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_stream_workflow.py +0 -0
  227. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_validation.py +0 -0
  228. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/tests/unit/test_workflow.py +0 -0
  229. {pyworkflow_engine-0.2.0b1 → pyworkflow_engine-0.2.1}/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.0b1
3
+ Version: 0.2.1
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.0b1"
10
+ version = "0.2.1"
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.0b1"
32
+ __version__ = "0.2.1"
33
33
 
34
34
  # Configuration
35
35
  from pyworkflow.config import (
@@ -198,14 +198,36 @@ def execute_step_task(
198
198
  _exec_lock_key, self.request.id or "unknown", expiry=self._lock_expiry
199
199
  )
200
200
  if not _exec_lock_acquired:
201
- logger.warning(
202
- "Step already being executed by another worker, skipping duplicate",
203
- run_id=run_id,
204
- step_id=step_id,
205
- step_name=step_name,
206
- existing_worker_task=_exec_lock_backend.get(_exec_lock_key),
207
- )
208
- return None
201
+ # Check for worker-loss re-delivery: when a worker dies mid-step
202
+ # (e.g., spot instance termination), Celery re-delivers the same
203
+ # message with the same task_id (task_reject_on_worker_lost=True).
204
+ # The dead worker's lock still exists in Redis (up to 1h TTL).
205
+ # If the lock holder matches our own task_id, this IS a re-delivery
206
+ # of the same task — force-acquire and proceed.
207
+ _holding_task_id = _exec_lock_backend.get(_exec_lock_key)
208
+ _our_task_id = self.request.id or "unknown"
209
+ if _holding_task_id == _our_task_id:
210
+ logger.warning(
211
+ "Step lock held by same task_id — worker-loss re-delivery detected, "
212
+ "force-acquiring lock",
213
+ run_id=run_id,
214
+ step_id=step_id,
215
+ step_name=step_name,
216
+ task_id=_our_task_id,
217
+ )
218
+ _exec_lock_backend.unlock(_exec_lock_key)
219
+ _exec_lock_acquired = _exec_lock_backend.lock(
220
+ _exec_lock_key, _our_task_id, expiry=self._lock_expiry
221
+ )
222
+ else:
223
+ logger.warning(
224
+ "Step already being executed by another worker, skipping duplicate",
225
+ run_id=run_id,
226
+ step_id=step_id,
227
+ step_name=step_name,
228
+ existing_worker_task=_holding_task_id,
229
+ )
230
+ return None
209
231
  else:
210
232
  _exec_lock_acquired = True # No Redis = no locking
211
233
 
@@ -871,18 +893,38 @@ def start_workflow_task(
871
893
  _exec_lock_key = f"pyworkflow:wf_start:{run_id}"
872
894
  _exec_lock_backend = self.singleton_backend
873
895
  _exec_lock_acquired = False
896
+ _is_redelivery = False
874
897
  if _exec_lock_backend is not None:
875
898
  _exec_lock_acquired = _exec_lock_backend.lock(
876
899
  _exec_lock_key, self.request.id or "unknown", expiry=self._lock_expiry
877
900
  )
878
901
  if not _exec_lock_acquired:
879
- logger.warning(
880
- "Workflow start already being executed by another worker, skipping duplicate",
881
- run_id=run_id,
882
- workflow_name=workflow_name,
883
- existing_worker_task=_exec_lock_backend.get(_exec_lock_key),
884
- )
885
- return run_id
902
+ # Check for worker-loss re-delivery (same logic as step tasks):
903
+ # if the lock holder matches our task_id, this is the same message
904
+ # re-delivered after the original worker died.
905
+ _holding_task_id = _exec_lock_backend.get(_exec_lock_key)
906
+ _our_task_id = self.request.id or "unknown"
907
+ if _holding_task_id == _our_task_id:
908
+ logger.warning(
909
+ "Workflow start lock held by same task_id — worker-loss re-delivery "
910
+ "detected, force-acquiring lock",
911
+ run_id=run_id,
912
+ workflow_name=workflow_name,
913
+ task_id=_our_task_id,
914
+ )
915
+ _exec_lock_backend.unlock(_exec_lock_key)
916
+ _exec_lock_acquired = _exec_lock_backend.lock(
917
+ _exec_lock_key, _our_task_id, expiry=self._lock_expiry
918
+ )
919
+ _is_redelivery = True
920
+ else:
921
+ logger.warning(
922
+ "Workflow start already being executed by another worker, skipping duplicate",
923
+ run_id=run_id,
924
+ workflow_name=workflow_name,
925
+ existing_worker_task=_holding_task_id,
926
+ )
927
+ return run_id
886
928
  else:
887
929
  _exec_lock_acquired = True # No Redis = no locking
888
930
 
@@ -909,6 +951,7 @@ def start_workflow_task(
909
951
  storage_config=storage_config,
910
952
  idempotency_key=idempotency_key,
911
953
  run_id=run_id,
954
+ is_redelivery=_is_redelivery,
912
955
  )
913
956
  )
914
957
 
@@ -1588,6 +1631,7 @@ async def _start_workflow_on_worker(
1588
1631
  storage_config: dict[str, Any] | None = None,
1589
1632
  idempotency_key: str | None = None,
1590
1633
  run_id: str | None = None,
1634
+ is_redelivery: bool = False,
1591
1635
  ) -> str:
1592
1636
  """
1593
1637
  Internal function to start workflow on Celery worker.
@@ -1603,6 +1647,10 @@ async def _start_workflow_on_worker(
1603
1647
  storage_config: Storage configuration for child tasks
1604
1648
  idempotency_key: Optional idempotency key
1605
1649
  run_id: Pre-generated run ID (if None, generates a new one)
1650
+ is_redelivery: True when Celery re-delivered the same task_id after
1651
+ worker loss. Re-deliveries bypass the recovery_attempts counter
1652
+ since they represent the same logical execution, not an additional
1653
+ recovery attempt.
1606
1654
  """
1607
1655
  from pyworkflow.config import get_config
1608
1656
 
@@ -1643,6 +1691,24 @@ async def _start_workflow_on_worker(
1643
1691
  )
1644
1692
  return existing_run.run_id
1645
1693
 
1694
+ if is_redelivery:
1695
+ # Celery re-delivered the same task after worker loss.
1696
+ # This is NOT an extra recovery attempt — it is the same
1697
+ # logical execution being retried by the broker. Skip the
1698
+ # recovery-attempts counter and go straight to replay.
1699
+ logger.info(
1700
+ "Worker-loss re-delivery: recovering without counting "
1701
+ "against max_recovery_attempts",
1702
+ run_id=existing_run.run_id,
1703
+ workflow_name=existing_run.workflow_name,
1704
+ )
1705
+ return await _recover_workflow_on_worker(
1706
+ run=existing_run,
1707
+ workflow_meta=workflow_meta,
1708
+ storage=storage,
1709
+ storage_config=storage_config,
1710
+ )
1711
+
1646
1712
  # This is a recovery scenario - worker crashed while running
1647
1713
  can_recover = await _handle_workflow_recovery(
1648
1714
  run=existing_run,
@@ -1699,6 +1765,22 @@ async def _start_workflow_on_worker(
1699
1765
  )
1700
1766
 
1701
1767
  if existing_run.status == RunStatus.RUNNING:
1768
+ if is_redelivery:
1769
+ # Celery re-delivered the same task after worker loss.
1770
+ # Skip recovery-attempts counter — same logical execution.
1771
+ logger.info(
1772
+ "Worker-loss re-delivery: recovering without counting "
1773
+ "against max_recovery_attempts",
1774
+ run_id=run_id,
1775
+ workflow_name=existing_run.workflow_name,
1776
+ )
1777
+ return await _recover_workflow_on_worker(
1778
+ run=existing_run,
1779
+ workflow_meta=workflow_meta,
1780
+ storage=storage,
1781
+ storage_config=storage_config,
1782
+ )
1783
+
1702
1784
  # Recovery scenario - worker crashed while running
1703
1785
  can_recover = await _handle_workflow_recovery(
1704
1786
  run=existing_run,