pyworkflow-engine 0.1.7__tar.gz → 0.1.9__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.
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/PKG-INFO +7 -4
- pyworkflow_engine-0.1.9/docs/concepts/step-context.mdx +364 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/steps.mdx +3 -3
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/workflows.mdx +3 -3
- pyworkflow_engine-0.1.9/examples/celery/durable/workflows/step_context.py +307 -0
- pyworkflow_engine-0.1.9/examples/local/durable/13_step_context.py +221 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyproject.toml +18 -6
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/__init__.py +10 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/celery/tasks.py +272 -24
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/__init__.py +4 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/runs.py +4 -4
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/setup.py +203 -4
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/config_generator.py +76 -3
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/docker_manager.py +232 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/context/__init__.py +13 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/context/base.py +26 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/context/local.py +80 -0
- pyworkflow_engine-0.1.9/pyworkflow/context/step_context.py +295 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/registry.py +6 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/step.py +141 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/workflow.py +56 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/engine/events.py +30 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/engine/replay.py +39 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/child_workflow.py +1 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/runtime/local.py +1 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/__init__.py +14 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/base.py +35 -0
- pyworkflow_engine-0.1.9/pyworkflow/storage/cassandra.py +1747 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/config.py +69 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/dynamodb.py +31 -2
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/file.py +28 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/memory.py +18 -0
- pyworkflow_engine-0.1.9/pyworkflow/storage/mysql.py +1159 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/postgres.py +27 -2
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/schemas.py +4 -3
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/storage/sqlite.py +25 -2
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow_engine.egg-info/SOURCES.txt +9 -27
- pyworkflow_engine-0.1.9/tests/integration/test_cassandra_storage.py +1041 -0
- pyworkflow_engine-0.1.9/tests/unit/backends/test_cassandra_storage.py +996 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/backends/test_postgres_storage.py +1 -1
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/backends/test_sqlite_storage.py +1 -1
- pyworkflow_engine-0.1.9/tests/unit/test_step_context.py +456 -0
- pyworkflow_engine-0.1.7/dashboard/backend/app/__init__.py +0 -1
- pyworkflow_engine-0.1.7/dashboard/backend/app/config.py +0 -32
- pyworkflow_engine-0.1.7/dashboard/backend/app/controllers/__init__.py +0 -6
- pyworkflow_engine-0.1.7/dashboard/backend/app/controllers/run_controller.py +0 -86
- pyworkflow_engine-0.1.7/dashboard/backend/app/controllers/workflow_controller.py +0 -33
- pyworkflow_engine-0.1.7/dashboard/backend/app/dependencies/__init__.py +0 -5
- pyworkflow_engine-0.1.7/dashboard/backend/app/dependencies/storage.py +0 -50
- pyworkflow_engine-0.1.7/dashboard/backend/app/repositories/__init__.py +0 -6
- pyworkflow_engine-0.1.7/dashboard/backend/app/repositories/run_repository.py +0 -80
- pyworkflow_engine-0.1.7/dashboard/backend/app/repositories/workflow_repository.py +0 -27
- pyworkflow_engine-0.1.7/dashboard/backend/app/rest/__init__.py +0 -8
- pyworkflow_engine-0.1.7/dashboard/backend/app/rest/v1/__init__.py +0 -12
- pyworkflow_engine-0.1.7/dashboard/backend/app/rest/v1/health.py +0 -33
- pyworkflow_engine-0.1.7/dashboard/backend/app/rest/v1/runs.py +0 -133
- pyworkflow_engine-0.1.7/dashboard/backend/app/rest/v1/workflows.py +0 -41
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/__init__.py +0 -23
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/common.py +0 -16
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/event.py +0 -24
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/hook.py +0 -25
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/run.py +0 -54
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/step.py +0 -28
- pyworkflow_engine-0.1.7/dashboard/backend/app/schemas/workflow.py +0 -31
- pyworkflow_engine-0.1.7/dashboard/backend/app/server.py +0 -87
- pyworkflow_engine-0.1.7/dashboard/backend/app/services/__init__.py +0 -6
- pyworkflow_engine-0.1.7/dashboard/backend/app/services/run_service.py +0 -240
- pyworkflow_engine-0.1.7/dashboard/backend/app/services/workflow_service.py +0 -155
- pyworkflow_engine-0.1.7/dashboard/backend/main.py +0 -18
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/CLAUDE.md +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/DISTRIBUTED.md +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/LICENSE +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/MANIFEST.in +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/README.md +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/RELEASING.md +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/cancellation.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/continue-as-new.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/events.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/fault-tolerance.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/hooks.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/limitations.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/schedules.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/concepts/sleep.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/guides/cli.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/guides/configuration.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/introduction.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/docs/quickstart.mdx +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/docker-compose.yml +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/pyworkflow.config.yaml +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/basic.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/batch_processing.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/cancellation.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/child_workflow_patterns.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/child_workflows.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/continue_as_new.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/fault_tolerance.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/hooks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/idempotency.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/long_running.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/retries.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/durable/workflows/schedules.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/transient/01_basic_workflow.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/transient/02_fault_tolerance.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/transient/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/celery/transient/pyworkflow.config.yaml +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/01_basic_workflow.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/02_file_storage.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/03_retries.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/04_long_running.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/05_event_log.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/06_idempotency.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/07_hooks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/08_cancellation.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/09_child_workflows.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/10_child_workflow_patterns.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/11_continue_as_new.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/12_schedules.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/durable/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/transient/01_quick_tasks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/transient/02_retries.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/transient/03_sleep.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/examples/local/transient/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/aws/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/aws/context.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/aws/handler.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/aws/testing.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/celery/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/celery/app.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/celery/scheduler.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/__main__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/hooks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/quickstart.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/scheduler.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/schedules.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/worker.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/commands/workflows.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/output/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/output/formatters.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/output/styles.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/async_helpers.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/config.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/discovery.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/interactive.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/cli/utils/storage.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/config.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/context/aws.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/context/mock.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/exceptions.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/core/scheduled.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/discovery.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/engine/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/engine/executor.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/observability/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/observability/logging.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/child_handle.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/continue_as_new.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/define_hook.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/hooks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/resume_hook.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/schedule.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/shield.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/primitives/sleep.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/runtime/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/runtime/base.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/runtime/celery.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/runtime/factory.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/scheduler/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/scheduler/local.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/serialization/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/serialization/decoder.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/serialization/encoder.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/utils/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/utils/duration.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/pyworkflow/utils/schedule.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/setup.cfg +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/examples/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_cancellation.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_child_workflows.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_continue_as_new.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_dynamodb_storage.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_fault_tolerance.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/integration/test_schedule_storage.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/backends/__init__.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/backends/test_dynamodb_storage.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/conftest.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_cancellation.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_child_workflows.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_continue_as_new.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_event_limits.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_executor.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_fault_tolerance.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_hooks.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_registry.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_replay.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_schedule_schemas.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_schedule_utils.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_scheduled_workflow.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_step.py +0 -0
- {pyworkflow_engine-0.1.7 → pyworkflow_engine-0.1.9}/tests/unit/test_workflow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyworkflow-engine
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: A Python implementation of durable, event-sourced workflows inspired by Vercel Workflow
|
|
5
5
|
Author: PyWorkflow Contributors
|
|
6
6
|
License: MIT
|
|
@@ -35,7 +35,6 @@ Requires-Dist: pyyaml>=6.0.0
|
|
|
35
35
|
Requires-Dist: croniter>=2.0.0
|
|
36
36
|
Provides-Extra: redis
|
|
37
37
|
Requires-Dist: redis>=5.0.0; extra == "redis"
|
|
38
|
-
Requires-Dist: celery[redis]<6.0.0,>=5.3.0; extra == "redis"
|
|
39
38
|
Provides-Extra: sqlite
|
|
40
39
|
Requires-Dist: aiosqlite>=0.19.0; extra == "sqlite"
|
|
41
40
|
Provides-Extra: postgres
|
|
@@ -44,12 +43,17 @@ Provides-Extra: aws
|
|
|
44
43
|
Requires-Dist: aws-durable-execution-sdk-python>=0.1.0; extra == "aws"
|
|
45
44
|
Provides-Extra: dynamodb
|
|
46
45
|
Requires-Dist: aiobotocore>=2.5.0; extra == "dynamodb"
|
|
46
|
+
Provides-Extra: cassandra
|
|
47
|
+
Requires-Dist: cassandra-driver>=3.29.0; extra == "cassandra"
|
|
48
|
+
Provides-Extra: mysql
|
|
49
|
+
Requires-Dist: aiomysql>=0.2.0; extra == "mysql"
|
|
47
50
|
Provides-Extra: all
|
|
48
51
|
Requires-Dist: redis>=5.0.0; extra == "all"
|
|
49
|
-
Requires-Dist: celery[redis]<6.0.0,>=5.3.0; extra == "all"
|
|
50
52
|
Requires-Dist: aiosqlite>=0.19.0; extra == "all"
|
|
51
53
|
Requires-Dist: asyncpg>=0.29.0; extra == "all"
|
|
54
|
+
Requires-Dist: aiomysql>=0.2.0; extra == "all"
|
|
52
55
|
Requires-Dist: aws-durable-execution-sdk-python>=0.1.0; extra == "all"
|
|
56
|
+
Requires-Dist: cassandra-driver>=3.29.0; extra == "all"
|
|
53
57
|
Provides-Extra: dev
|
|
54
58
|
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
55
59
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -66,7 +70,6 @@ Requires-Dist: types-python-dateutil>=2.8.0; extra == "dev"
|
|
|
66
70
|
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
|
|
67
71
|
Requires-Dist: flower>=2.0.0; extra == "dev"
|
|
68
72
|
Requires-Dist: redis>=5.0.0; extra == "dev"
|
|
69
|
-
Requires-Dist: celery[redis]<6.0.0,>=5.3.0; extra == "dev"
|
|
70
73
|
Requires-Dist: aiosqlite>=0.19.0; extra == "dev"
|
|
71
74
|
Requires-Dist: asyncpg>=0.29.0; extra == "dev"
|
|
72
75
|
Dynamic: license-file
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Step Context'
|
|
3
|
+
description: 'Share typed, read-only context data between workflows and distributed steps'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## What is Step Context?
|
|
7
|
+
|
|
8
|
+
Step Context provides a way to share workflow-level data with steps executing on remote Celery workers. Unlike the workflow context which is process-local, Step Context is serialized and passed to workers, making it accessible in distributed step execution.
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
from pyworkflow import workflow, step, StepContext, get_step_context, set_step_context
|
|
12
|
+
|
|
13
|
+
class OrderContext(StepContext):
|
|
14
|
+
workspace_id: str = ""
|
|
15
|
+
user_id: str = ""
|
|
16
|
+
order_id: str = ""
|
|
17
|
+
|
|
18
|
+
@workflow(context_class=OrderContext)
|
|
19
|
+
async def process_order(order_id: str, user_id: str):
|
|
20
|
+
# Initialize context in workflow
|
|
21
|
+
ctx = OrderContext(order_id=order_id, user_id=user_id)
|
|
22
|
+
await set_step_context(ctx)
|
|
23
|
+
|
|
24
|
+
# Steps can read the context
|
|
25
|
+
result = await validate_order()
|
|
26
|
+
return result
|
|
27
|
+
|
|
28
|
+
@step()
|
|
29
|
+
async def validate_order():
|
|
30
|
+
ctx = get_step_context() # Read-only access
|
|
31
|
+
print(f"Validating order {ctx.order_id} for user {ctx.user_id}")
|
|
32
|
+
return {"valid": True}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Characteristics
|
|
36
|
+
|
|
37
|
+
<CardGroup cols={2}>
|
|
38
|
+
<Card title="Type-Safe" icon="shield-check">
|
|
39
|
+
Define typed context fields using Pydantic models with full IDE support.
|
|
40
|
+
</Card>
|
|
41
|
+
<Card title="Read-Only in Steps" icon="lock">
|
|
42
|
+
Context is read-only during step execution to prevent race conditions.
|
|
43
|
+
</Card>
|
|
44
|
+
<Card title="Distributed" icon="server">
|
|
45
|
+
Context is automatically serialized and passed to Celery workers.
|
|
46
|
+
</Card>
|
|
47
|
+
<Card title="Event-Sourced" icon="database">
|
|
48
|
+
Context changes are recorded as events for deterministic replay.
|
|
49
|
+
</Card>
|
|
50
|
+
</CardGroup>
|
|
51
|
+
|
|
52
|
+
## Why Read-Only in Steps?
|
|
53
|
+
|
|
54
|
+
When steps execute in parallel on different workers, allowing them to modify shared context would cause race conditions:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Worker A: read context → modify → save ─┐
|
|
58
|
+
├─> Lost update!
|
|
59
|
+
Worker B: read context → modify → save ─┘
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
By making context read-only in steps, PyWorkflow follows the same pattern used by [Temporal](https://temporal.io) and [Prefect](https://prefect.io) - activities/tasks are stateless, and state mutations happen through return values in the workflow.
|
|
63
|
+
|
|
64
|
+
<Info>
|
|
65
|
+
If you need to update context based on step results, do it in the workflow code after the step returns.
|
|
66
|
+
</Info>
|
|
67
|
+
|
|
68
|
+
## Defining a Context Class
|
|
69
|
+
|
|
70
|
+
Create a context class by extending `StepContext`:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from pyworkflow import StepContext
|
|
74
|
+
|
|
75
|
+
class FlowContext(StepContext):
|
|
76
|
+
# Required fields (no default)
|
|
77
|
+
workspace_id: str
|
|
78
|
+
|
|
79
|
+
# Optional fields (with defaults)
|
|
80
|
+
user_id: str = ""
|
|
81
|
+
request_id: str = ""
|
|
82
|
+
tags: list[str] = []
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Immutable by Design
|
|
86
|
+
|
|
87
|
+
Step Context is immutable (frozen). To update values, use `with_updates()` which creates a new instance:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
ctx = FlowContext(workspace_id="ws-123")
|
|
91
|
+
print(ctx.workspace_id) # "ws-123"
|
|
92
|
+
|
|
93
|
+
# Create new context with updated values
|
|
94
|
+
ctx = ctx.with_updates(user_id="user-456", request_id="req-789")
|
|
95
|
+
print(ctx.user_id) # "user-456"
|
|
96
|
+
|
|
97
|
+
# Original values are preserved
|
|
98
|
+
print(ctx.workspace_id) # "ws-123"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
<Warning>
|
|
102
|
+
Direct attribute assignment raises an error:
|
|
103
|
+
```python
|
|
104
|
+
ctx.user_id = "new-value" # ValidationError!
|
|
105
|
+
```
|
|
106
|
+
</Warning>
|
|
107
|
+
|
|
108
|
+
## Using Step Context
|
|
109
|
+
|
|
110
|
+
### Setting Context (Workflow Only)
|
|
111
|
+
|
|
112
|
+
Use `set_step_context()` to set or update the context. This can only be called from workflow code:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from pyworkflow import workflow, set_step_context
|
|
116
|
+
|
|
117
|
+
@workflow(context_class=OrderContext)
|
|
118
|
+
async def my_workflow(user_id: str):
|
|
119
|
+
# Initialize context
|
|
120
|
+
ctx = OrderContext(user_id=user_id, workspace_id="ws-123")
|
|
121
|
+
await set_step_context(ctx) # Note: async function
|
|
122
|
+
|
|
123
|
+
# ... execute steps ...
|
|
124
|
+
|
|
125
|
+
# Update context (creates new instance)
|
|
126
|
+
ctx = get_step_context()
|
|
127
|
+
ctx = ctx.with_updates(order_id="order-456")
|
|
128
|
+
await set_step_context(ctx)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
<Note>
|
|
132
|
+
`set_step_context()` is an async function because it persists the context to storage and records a `CONTEXT_UPDATED` event.
|
|
133
|
+
</Note>
|
|
134
|
+
|
|
135
|
+
### Reading Context (Workflow and Steps)
|
|
136
|
+
|
|
137
|
+
Use `get_step_context()` to access the current context from anywhere:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from pyworkflow import step, get_step_context
|
|
141
|
+
|
|
142
|
+
@step()
|
|
143
|
+
async def send_notification():
|
|
144
|
+
ctx = get_step_context()
|
|
145
|
+
|
|
146
|
+
await notify_user(
|
|
147
|
+
user_id=ctx.user_id,
|
|
148
|
+
workspace_id=ctx.workspace_id,
|
|
149
|
+
message=f"Order {ctx.order_id} processed"
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Checking Context Availability
|
|
154
|
+
|
|
155
|
+
Use `has_step_context()` to check if context is available:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from pyworkflow import has_step_context, get_step_context
|
|
159
|
+
|
|
160
|
+
@step()
|
|
161
|
+
async def optional_logging():
|
|
162
|
+
if has_step_context():
|
|
163
|
+
ctx = get_step_context()
|
|
164
|
+
logger.info(f"Processing in workspace {ctx.workspace_id}")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Read-Only Enforcement
|
|
168
|
+
|
|
169
|
+
Attempting to set context from within a step raises a `RuntimeError`:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
@step()
|
|
173
|
+
async def my_step():
|
|
174
|
+
ctx = get_step_context()
|
|
175
|
+
|
|
176
|
+
# This works - reading context
|
|
177
|
+
print(ctx.workspace_id)
|
|
178
|
+
|
|
179
|
+
# This raises RuntimeError!
|
|
180
|
+
new_ctx = ctx.with_updates(workspace_id="new-ws")
|
|
181
|
+
await set_step_context(new_ctx) # RuntimeError: Cannot modify step context within a step
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
To update context based on step results, return data from the step and update in the workflow:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
@workflow(context_class=OrderContext)
|
|
188
|
+
async def process_order(order_id: str):
|
|
189
|
+
ctx = OrderContext(order_id=order_id)
|
|
190
|
+
await set_step_context(ctx)
|
|
191
|
+
|
|
192
|
+
# Step returns data instead of modifying context
|
|
193
|
+
validation_result = await validate_order()
|
|
194
|
+
|
|
195
|
+
# Update context in workflow based on step result
|
|
196
|
+
if validation_result["needs_review"]:
|
|
197
|
+
ctx = get_step_context()
|
|
198
|
+
ctx = ctx.with_updates(status="pending_review")
|
|
199
|
+
await set_step_context(ctx)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Context Persistence and Replay
|
|
203
|
+
|
|
204
|
+
Step Context is event-sourced for durability:
|
|
205
|
+
|
|
206
|
+
1. **Persistence**: When you call `set_step_context()`, the context is:
|
|
207
|
+
- Stored in the `WorkflowRun.context` field
|
|
208
|
+
- Recorded as a `CONTEXT_UPDATED` event
|
|
209
|
+
|
|
210
|
+
2. **Replay**: When a workflow resumes after suspension:
|
|
211
|
+
- Context is restored from the event log
|
|
212
|
+
- Steps receive the same context they had during original execution
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
@workflow(context_class=OrderContext)
|
|
216
|
+
async def durable_workflow(order_id: str):
|
|
217
|
+
ctx = OrderContext(order_id=order_id)
|
|
218
|
+
await set_step_context(ctx) # Persisted to storage
|
|
219
|
+
|
|
220
|
+
await some_step()
|
|
221
|
+
|
|
222
|
+
await sleep("1h") # Workflow suspends
|
|
223
|
+
|
|
224
|
+
# After 1 hour, workflow resumes
|
|
225
|
+
# Context is automatically restored from events
|
|
226
|
+
ctx = get_step_context()
|
|
227
|
+
print(ctx.order_id) # Still "order_id" - restored from replay
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Complex Context Types
|
|
231
|
+
|
|
232
|
+
Step Context supports complex nested types:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from pydantic import BaseModel
|
|
236
|
+
|
|
237
|
+
class Address(BaseModel):
|
|
238
|
+
street: str
|
|
239
|
+
city: str
|
|
240
|
+
country: str
|
|
241
|
+
|
|
242
|
+
model_config = {"frozen": True}
|
|
243
|
+
|
|
244
|
+
class CustomerContext(StepContext):
|
|
245
|
+
customer_id: str
|
|
246
|
+
email: str = ""
|
|
247
|
+
shipping_address: Address | None = None
|
|
248
|
+
metadata: dict[str, str] = {}
|
|
249
|
+
|
|
250
|
+
@workflow(context_class=CustomerContext)
|
|
251
|
+
async def ship_order(customer_id: str, address: dict):
|
|
252
|
+
ctx = CustomerContext(
|
|
253
|
+
customer_id=customer_id,
|
|
254
|
+
shipping_address=Address(**address)
|
|
255
|
+
)
|
|
256
|
+
await set_step_context(ctx)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
<Warning>
|
|
260
|
+
All context fields must be JSON-serializable. Avoid storing non-serializable objects like database connections or file handles.
|
|
261
|
+
</Warning>
|
|
262
|
+
|
|
263
|
+
## Best Practices
|
|
264
|
+
|
|
265
|
+
<AccordionGroup>
|
|
266
|
+
<Accordion title="Keep context small">
|
|
267
|
+
Store only essential cross-cutting data like IDs, user info, and configuration. Don't use context as a data store - pass large data as step arguments instead.
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
# Good - small, essential data
|
|
271
|
+
class GoodContext(StepContext):
|
|
272
|
+
workspace_id: str
|
|
273
|
+
user_id: str
|
|
274
|
+
request_id: str
|
|
275
|
+
|
|
276
|
+
# Bad - too much data
|
|
277
|
+
class BadContext(StepContext):
|
|
278
|
+
workspace_id: str
|
|
279
|
+
user_data: dict # Could be large
|
|
280
|
+
all_orders: list[dict] # Definitely too large
|
|
281
|
+
```
|
|
282
|
+
</Accordion>
|
|
283
|
+
|
|
284
|
+
<Accordion title="Use context for cross-cutting concerns">
|
|
285
|
+
Step Context is ideal for data needed by many steps: auth info, workspace IDs, correlation IDs, feature flags.
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
class RequestContext(StepContext):
|
|
289
|
+
workspace_id: str
|
|
290
|
+
user_id: str
|
|
291
|
+
correlation_id: str # For distributed tracing
|
|
292
|
+
feature_flags: dict[str, bool] = {}
|
|
293
|
+
```
|
|
294
|
+
</Accordion>
|
|
295
|
+
|
|
296
|
+
<Accordion title="Initialize context early">
|
|
297
|
+
Set up context at the beginning of your workflow before calling any steps.
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
@workflow(context_class=MyContext)
|
|
301
|
+
async def my_workflow(workspace_id: str, user_id: str):
|
|
302
|
+
# Initialize context first
|
|
303
|
+
ctx = MyContext(workspace_id=workspace_id, user_id=user_id)
|
|
304
|
+
await set_step_context(ctx)
|
|
305
|
+
|
|
306
|
+
# Now call steps
|
|
307
|
+
await step_one()
|
|
308
|
+
await step_two()
|
|
309
|
+
```
|
|
310
|
+
</Accordion>
|
|
311
|
+
|
|
312
|
+
<Accordion title="Don't store secrets in context">
|
|
313
|
+
Context is persisted to storage. Use secret managers or environment variables for sensitive data.
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
# Bad - secrets in context
|
|
317
|
+
class BadContext(StepContext):
|
|
318
|
+
api_key: str # Don't do this!
|
|
319
|
+
|
|
320
|
+
# Good - reference to secret, not the secret itself
|
|
321
|
+
class GoodContext(StepContext):
|
|
322
|
+
secret_name: str # Reference to secret in vault
|
|
323
|
+
|
|
324
|
+
@step()
|
|
325
|
+
async def call_api():
|
|
326
|
+
ctx = get_step_context()
|
|
327
|
+
api_key = await secret_manager.get(ctx.secret_name)
|
|
328
|
+
```
|
|
329
|
+
</Accordion>
|
|
330
|
+
</AccordionGroup>
|
|
331
|
+
|
|
332
|
+
## API Reference
|
|
333
|
+
|
|
334
|
+
| Function | Description |
|
|
335
|
+
|----------|-------------|
|
|
336
|
+
| `StepContext` | Base class for user-defined context |
|
|
337
|
+
| `get_step_context()` | Get current context (raises if not set) |
|
|
338
|
+
| `set_step_context(ctx)` | Set context (async, workflow only) |
|
|
339
|
+
| `has_step_context()` | Check if context is available |
|
|
340
|
+
|
|
341
|
+
### StepContext Methods
|
|
342
|
+
|
|
343
|
+
| Method | Description |
|
|
344
|
+
|--------|-------------|
|
|
345
|
+
| `with_updates(**kwargs)` | Create new context with updated fields |
|
|
346
|
+
| `to_dict()` | Serialize context to dictionary |
|
|
347
|
+
| `from_dict(data)` | Deserialize context from dictionary |
|
|
348
|
+
|
|
349
|
+
## Next Steps
|
|
350
|
+
|
|
351
|
+
<CardGroup cols={2}>
|
|
352
|
+
<Card title="Steps" icon="stairs" href="/concepts/steps">
|
|
353
|
+
Learn about steps - the building blocks that use context.
|
|
354
|
+
</Card>
|
|
355
|
+
<Card title="Events" icon="timeline" href="/concepts/events">
|
|
356
|
+
Understand how context changes are event-sourced.
|
|
357
|
+
</Card>
|
|
358
|
+
<Card title="Fault Tolerance" icon="shield-check" href="/concepts/fault-tolerance">
|
|
359
|
+
See how context survives crashes and restarts.
|
|
360
|
+
</Card>
|
|
361
|
+
<Card title="Configuration" icon="gear" href="/guides/configuration">
|
|
362
|
+
Configure storage backends for context persistence.
|
|
363
|
+
</Card>
|
|
364
|
+
</CardGroup>
|
|
@@ -292,10 +292,10 @@ async def load_dashboard(user_id: str):
|
|
|
292
292
|
## Next Steps
|
|
293
293
|
|
|
294
294
|
<CardGroup cols={2}>
|
|
295
|
+
<Card title="Step Context" icon="database" href="/concepts/step-context">
|
|
296
|
+
Share typed context data between workflows and distributed steps.
|
|
297
|
+
</Card>
|
|
295
298
|
<Card title="Events" icon="timeline" href="/concepts/events">
|
|
296
299
|
Learn how event sourcing enables durability and replay.
|
|
297
300
|
</Card>
|
|
298
|
-
<Card title="Error Handling" icon="shield-check" href="/guides/error-handling">
|
|
299
|
-
Deep dive into retry strategies and error handling.
|
|
300
|
-
</Card>
|
|
301
301
|
</CardGroup>
|
|
@@ -243,12 +243,12 @@ async def my_workflow():
|
|
|
243
243
|
<Card title="Steps" icon="stairs" href="/concepts/steps">
|
|
244
244
|
Learn about steps - the building blocks of workflows.
|
|
245
245
|
</Card>
|
|
246
|
+
<Card title="Step Context" icon="database" href="/concepts/step-context">
|
|
247
|
+
Share typed context data with distributed steps.
|
|
248
|
+
</Card>
|
|
246
249
|
<Card title="Schedules" icon="calendar" href="/concepts/schedules">
|
|
247
250
|
Automatically run workflows on cron, interval, or calendar schedules.
|
|
248
251
|
</Card>
|
|
249
|
-
<Card title="Sleep" icon="clock" href="/concepts/sleep">
|
|
250
|
-
Pause workflows for any duration without consuming resources.
|
|
251
|
-
</Card>
|
|
252
252
|
<Card title="Fault Tolerance" icon="shield-check" href="/concepts/fault-tolerance">
|
|
253
253
|
Configure auto recovery from worker crashes.
|
|
254
254
|
</Card>
|