pyworkflow-engine 0.1.7__py3-none-any.whl → 0.1.10__py3-none-any.whl
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.
- pyworkflow/__init__.py +10 -1
- pyworkflow/celery/tasks.py +272 -24
- pyworkflow/cli/__init__.py +4 -1
- pyworkflow/cli/commands/runs.py +4 -4
- pyworkflow/cli/commands/setup.py +203 -4
- pyworkflow/cli/utils/config_generator.py +76 -3
- pyworkflow/cli/utils/docker_manager.py +232 -0
- pyworkflow/config.py +94 -17
- pyworkflow/context/__init__.py +13 -0
- pyworkflow/context/base.py +26 -0
- pyworkflow/context/local.py +80 -0
- pyworkflow/context/step_context.py +295 -0
- pyworkflow/core/registry.py +6 -1
- pyworkflow/core/step.py +141 -0
- pyworkflow/core/workflow.py +56 -0
- pyworkflow/engine/events.py +30 -0
- pyworkflow/engine/replay.py +39 -0
- pyworkflow/primitives/child_workflow.py +1 -1
- pyworkflow/runtime/local.py +1 -1
- pyworkflow/storage/__init__.py +14 -0
- pyworkflow/storage/base.py +35 -0
- pyworkflow/storage/cassandra.py +1747 -0
- pyworkflow/storage/config.py +69 -0
- pyworkflow/storage/dynamodb.py +31 -2
- pyworkflow/storage/file.py +28 -0
- pyworkflow/storage/memory.py +18 -0
- pyworkflow/storage/mysql.py +1159 -0
- pyworkflow/storage/postgres.py +27 -2
- pyworkflow/storage/schemas.py +4 -3
- pyworkflow/storage/sqlite.py +25 -2
- {pyworkflow_engine-0.1.7.dist-info → pyworkflow_engine-0.1.10.dist-info}/METADATA +7 -4
- pyworkflow_engine-0.1.10.dist-info/RECORD +91 -0
- pyworkflow_engine-0.1.10.dist-info/top_level.txt +1 -0
- dashboard/backend/app/__init__.py +0 -1
- dashboard/backend/app/config.py +0 -32
- dashboard/backend/app/controllers/__init__.py +0 -6
- dashboard/backend/app/controllers/run_controller.py +0 -86
- dashboard/backend/app/controllers/workflow_controller.py +0 -33
- dashboard/backend/app/dependencies/__init__.py +0 -5
- dashboard/backend/app/dependencies/storage.py +0 -50
- dashboard/backend/app/repositories/__init__.py +0 -6
- dashboard/backend/app/repositories/run_repository.py +0 -80
- dashboard/backend/app/repositories/workflow_repository.py +0 -27
- dashboard/backend/app/rest/__init__.py +0 -8
- dashboard/backend/app/rest/v1/__init__.py +0 -12
- dashboard/backend/app/rest/v1/health.py +0 -33
- dashboard/backend/app/rest/v1/runs.py +0 -133
- dashboard/backend/app/rest/v1/workflows.py +0 -41
- dashboard/backend/app/schemas/__init__.py +0 -23
- dashboard/backend/app/schemas/common.py +0 -16
- dashboard/backend/app/schemas/event.py +0 -24
- dashboard/backend/app/schemas/hook.py +0 -25
- dashboard/backend/app/schemas/run.py +0 -54
- dashboard/backend/app/schemas/step.py +0 -28
- dashboard/backend/app/schemas/workflow.py +0 -31
- dashboard/backend/app/server.py +0 -87
- dashboard/backend/app/services/__init__.py +0 -6
- dashboard/backend/app/services/run_service.py +0 -240
- dashboard/backend/app/services/workflow_service.py +0 -155
- dashboard/backend/main.py +0 -18
- docs/concepts/cancellation.mdx +0 -362
- docs/concepts/continue-as-new.mdx +0 -434
- docs/concepts/events.mdx +0 -266
- docs/concepts/fault-tolerance.mdx +0 -370
- docs/concepts/hooks.mdx +0 -552
- docs/concepts/limitations.mdx +0 -167
- docs/concepts/schedules.mdx +0 -775
- docs/concepts/sleep.mdx +0 -312
- docs/concepts/steps.mdx +0 -301
- docs/concepts/workflows.mdx +0 -255
- docs/guides/cli.mdx +0 -942
- docs/guides/configuration.mdx +0 -560
- docs/introduction.mdx +0 -155
- docs/quickstart.mdx +0 -279
- examples/__init__.py +0 -1
- examples/celery/__init__.py +0 -1
- examples/celery/durable/docker-compose.yml +0 -55
- examples/celery/durable/pyworkflow.config.yaml +0 -12
- examples/celery/durable/workflows/__init__.py +0 -122
- examples/celery/durable/workflows/basic.py +0 -87
- examples/celery/durable/workflows/batch_processing.py +0 -102
- examples/celery/durable/workflows/cancellation.py +0 -273
- examples/celery/durable/workflows/child_workflow_patterns.py +0 -240
- examples/celery/durable/workflows/child_workflows.py +0 -202
- examples/celery/durable/workflows/continue_as_new.py +0 -260
- examples/celery/durable/workflows/fault_tolerance.py +0 -210
- examples/celery/durable/workflows/hooks.py +0 -211
- examples/celery/durable/workflows/idempotency.py +0 -112
- examples/celery/durable/workflows/long_running.py +0 -99
- examples/celery/durable/workflows/retries.py +0 -101
- examples/celery/durable/workflows/schedules.py +0 -209
- examples/celery/transient/01_basic_workflow.py +0 -91
- examples/celery/transient/02_fault_tolerance.py +0 -257
- examples/celery/transient/__init__.py +0 -20
- examples/celery/transient/pyworkflow.config.yaml +0 -25
- examples/local/__init__.py +0 -1
- examples/local/durable/01_basic_workflow.py +0 -94
- examples/local/durable/02_file_storage.py +0 -132
- examples/local/durable/03_retries.py +0 -169
- examples/local/durable/04_long_running.py +0 -119
- examples/local/durable/05_event_log.py +0 -145
- examples/local/durable/06_idempotency.py +0 -148
- examples/local/durable/07_hooks.py +0 -334
- examples/local/durable/08_cancellation.py +0 -233
- examples/local/durable/09_child_workflows.py +0 -198
- examples/local/durable/10_child_workflow_patterns.py +0 -265
- examples/local/durable/11_continue_as_new.py +0 -249
- examples/local/durable/12_schedules.py +0 -198
- examples/local/durable/__init__.py +0 -1
- examples/local/transient/01_quick_tasks.py +0 -87
- examples/local/transient/02_retries.py +0 -130
- examples/local/transient/03_sleep.py +0 -141
- examples/local/transient/__init__.py +0 -1
- pyworkflow_engine-0.1.7.dist-info/RECORD +0 -196
- pyworkflow_engine-0.1.7.dist-info/top_level.txt +0 -5
- tests/examples/__init__.py +0 -0
- tests/integration/__init__.py +0 -0
- tests/integration/test_cancellation.py +0 -330
- tests/integration/test_child_workflows.py +0 -439
- tests/integration/test_continue_as_new.py +0 -428
- tests/integration/test_dynamodb_storage.py +0 -1146
- tests/integration/test_fault_tolerance.py +0 -369
- tests/integration/test_schedule_storage.py +0 -484
- tests/unit/__init__.py +0 -0
- tests/unit/backends/__init__.py +0 -1
- tests/unit/backends/test_dynamodb_storage.py +0 -1554
- tests/unit/backends/test_postgres_storage.py +0 -1281
- tests/unit/backends/test_sqlite_storage.py +0 -1460
- tests/unit/conftest.py +0 -41
- tests/unit/test_cancellation.py +0 -364
- tests/unit/test_child_workflows.py +0 -680
- tests/unit/test_continue_as_new.py +0 -441
- tests/unit/test_event_limits.py +0 -316
- tests/unit/test_executor.py +0 -320
- tests/unit/test_fault_tolerance.py +0 -334
- tests/unit/test_hooks.py +0 -495
- tests/unit/test_registry.py +0 -261
- tests/unit/test_replay.py +0 -420
- tests/unit/test_schedule_schemas.py +0 -285
- tests/unit/test_schedule_utils.py +0 -286
- tests/unit/test_scheduled_workflow.py +0 -274
- tests/unit/test_step.py +0 -353
- tests/unit/test_workflow.py +0 -243
- {pyworkflow_engine-0.1.7.dist-info → pyworkflow_engine-0.1.10.dist-info}/WHEEL +0 -0
- {pyworkflow_engine-0.1.7.dist-info → pyworkflow_engine-0.1.10.dist-info}/entry_points.txt +0 -0
- {pyworkflow_engine-0.1.7.dist-info → pyworkflow_engine-0.1.10.dist-info}/licenses/LICENSE +0 -0
pyworkflow/engine/replay.py
CHANGED
|
@@ -93,6 +93,9 @@ class EventReplayer:
|
|
|
93
93
|
elif event.type == EventType.CANCELLATION_REQUESTED:
|
|
94
94
|
await self._apply_cancellation_requested(ctx, event)
|
|
95
95
|
|
|
96
|
+
elif event.type == EventType.CONTEXT_UPDATED:
|
|
97
|
+
await self._apply_context_updated(ctx, event)
|
|
98
|
+
|
|
96
99
|
# Other event types don't affect replay state
|
|
97
100
|
# (workflow_started, step_started, step_failed, etc. are informational)
|
|
98
101
|
|
|
@@ -255,6 +258,42 @@ class EventReplayer:
|
|
|
255
258
|
requested_by=requested_by,
|
|
256
259
|
)
|
|
257
260
|
|
|
261
|
+
async def _apply_context_updated(self, ctx: LocalContext, event: Event) -> None:
|
|
262
|
+
"""
|
|
263
|
+
Apply context_updated event - restore step context.
|
|
264
|
+
|
|
265
|
+
During replay, this restores the step context to its state at the time
|
|
266
|
+
the event was recorded. This ensures deterministic replay.
|
|
267
|
+
"""
|
|
268
|
+
from pyworkflow.context.step_context import (
|
|
269
|
+
_set_step_context_internal,
|
|
270
|
+
get_step_context_class,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
context_data = event.data.get("context", {})
|
|
274
|
+
|
|
275
|
+
if context_data:
|
|
276
|
+
# Get the registered context class
|
|
277
|
+
context_class = get_step_context_class()
|
|
278
|
+
if context_class is not None:
|
|
279
|
+
try:
|
|
280
|
+
step_ctx = context_class.from_dict(context_data)
|
|
281
|
+
_set_step_context_internal(step_ctx)
|
|
282
|
+
logger.debug(
|
|
283
|
+
"Restored step context from replay",
|
|
284
|
+
run_id=ctx.run_id,
|
|
285
|
+
)
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logger.warning(
|
|
288
|
+
f"Failed to restore step context: {e}",
|
|
289
|
+
run_id=ctx.run_id,
|
|
290
|
+
)
|
|
291
|
+
else:
|
|
292
|
+
logger.debug(
|
|
293
|
+
"No context class registered, skipping context restoration",
|
|
294
|
+
run_id=ctx.run_id,
|
|
295
|
+
)
|
|
296
|
+
|
|
258
297
|
|
|
259
298
|
# Singleton instance
|
|
260
299
|
_replayer = EventReplayer()
|
|
@@ -346,7 +346,7 @@ async def _start_child_on_worker(
|
|
|
346
346
|
parent_run_id=ctx.run_id,
|
|
347
347
|
nesting_depth=child_depth,
|
|
348
348
|
max_duration=workflow_meta.max_duration,
|
|
349
|
-
|
|
349
|
+
context={}, # Step context
|
|
350
350
|
)
|
|
351
351
|
await storage.create_run(child_run)
|
|
352
352
|
|
pyworkflow/runtime/local.py
CHANGED
pyworkflow/storage/__init__.py
CHANGED
|
@@ -35,6 +35,18 @@ try:
|
|
|
35
35
|
except ImportError:
|
|
36
36
|
DynamoDBStorageBackend = None # type: ignore
|
|
37
37
|
|
|
38
|
+
# Cassandra backend - optional import (requires cassandra-driver)
|
|
39
|
+
try:
|
|
40
|
+
from pyworkflow.storage.cassandra import CassandraStorageBackend
|
|
41
|
+
except ImportError:
|
|
42
|
+
CassandraStorageBackend = None # type: ignore
|
|
43
|
+
|
|
44
|
+
# MySQL backend - optional import (requires aiomysql)
|
|
45
|
+
try:
|
|
46
|
+
from pyworkflow.storage.mysql import MySQLStorageBackend
|
|
47
|
+
except ImportError:
|
|
48
|
+
MySQLStorageBackend = None # type: ignore
|
|
49
|
+
|
|
38
50
|
__all__ = [
|
|
39
51
|
"StorageBackend",
|
|
40
52
|
"FileStorageBackend",
|
|
@@ -42,6 +54,8 @@ __all__ = [
|
|
|
42
54
|
"SQLiteStorageBackend",
|
|
43
55
|
"PostgresStorageBackend",
|
|
44
56
|
"DynamoDBStorageBackend",
|
|
57
|
+
"CassandraStorageBackend",
|
|
58
|
+
"MySQLStorageBackend",
|
|
45
59
|
"WorkflowRun",
|
|
46
60
|
"StepExecution",
|
|
47
61
|
"Hook",
|
pyworkflow/storage/base.py
CHANGED
|
@@ -109,6 +109,41 @@ class StorageBackend(ABC):
|
|
|
109
109
|
"""
|
|
110
110
|
pass
|
|
111
111
|
|
|
112
|
+
@abstractmethod
|
|
113
|
+
async def update_run_context(
|
|
114
|
+
self,
|
|
115
|
+
run_id: str,
|
|
116
|
+
context: dict,
|
|
117
|
+
) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Update the step context for a workflow run.
|
|
120
|
+
|
|
121
|
+
Called when set_step_context() is invoked in workflow code.
|
|
122
|
+
The context is stored and can be loaded by steps running on
|
|
123
|
+
remote workers.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
run_id: Workflow run identifier
|
|
127
|
+
context: Context data as a dictionary (serialized StepContext)
|
|
128
|
+
"""
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
@abstractmethod
|
|
132
|
+
async def get_run_context(self, run_id: str) -> dict:
|
|
133
|
+
"""
|
|
134
|
+
Get the current step context for a workflow run.
|
|
135
|
+
|
|
136
|
+
Called when a step starts execution on a remote worker to
|
|
137
|
+
load the context that was set by the workflow.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
run_id: Workflow run identifier
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Context data as a dictionary, or empty dict if not set
|
|
144
|
+
"""
|
|
145
|
+
pass
|
|
146
|
+
|
|
112
147
|
@abstractmethod
|
|
113
148
|
async def list_runs(
|
|
114
149
|
self,
|