prefect-client 3.7.1.dev2__tar.gz → 3.7.1.dev3__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.
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/PKG-INFO +1 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/AGENTS.md +1 -0
- prefect_client-3.7.1.dev3/src/prefect/_build_info.py +5 -0
- prefect_client-3.7.1.dev3/src/prefect/_flow_run_suspension.py +136 -0
- prefect_client-3.7.1.dev3/src/prefect/_observers.py +494 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/__init__.py +1 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/AGENTS.md +1 -0
- prefect_client-3.7.1.dev3/src/prefect/client/schemas/worker_channel.py +590 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/context.py +8 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/flow_engine.py +84 -5
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/flow_runs.py +5 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/futures.py +21 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/AGENTS.md +1 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/loggers.py +12 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/AGENTS.md +1 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_cancellation_manager.py +21 -10
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_deployment_registry.py +10 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_starter_bundle.py +1 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_starter_direct.py +5 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_starter_engine.py +8 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_workspace_starter.py +3 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/runner.py +34 -5
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/task_engine.py +11 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/task_runners.py +3 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/tasks.py +7 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/processutils/AGENTS.md +1 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/processutils/__init__.py +12 -1
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/schema_tools/AGENTS.md +1 -1
- prefect_client-3.7.1.dev2/src/prefect/_build_info.py +0 -5
- prefect_client-3.7.1.dev2/src/prefect/_observers.py +0 -245
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/.gitignore +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/LICENSE +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/README.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/hatch_build.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/pyproject.toml +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/.prefectignore +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/__main__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/_launchers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/bundles/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/bundles/execute.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/plugins/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/plugins/apply.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/plugins/diagnostics.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/plugins/manager.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/plugins/spec.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/sla/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/sla/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_experimental/sla/objects.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/_logging.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/ci_detection.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/device_id.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/emit.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/enabled.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/milestones.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/notice.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/analytics/service.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/async_dispatch.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/backports.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/blocks.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/deprecated.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/deprecated_paths.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/migration.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/compatibility/starlette.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/api.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/calls.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/cancellation.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/event_loop.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/inspection.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/primitives.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/services.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/threads.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/concurrency/waiters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/control_listener.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/installation.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/integrations.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/lazy.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/observability.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/apply.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/collections.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/diagnostics.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/manager.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/spec.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/plugins/startup.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pydantic/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pydantic/schemas.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pydantic/v1_schema.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pydantic/v2_schema.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pydantic/validated_func.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/pytz.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/retries.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/schemas/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/schemas/bases.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/schemas/fields.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/schemas/serializers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/schemas/validators.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/send_entrypoint_logs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/testing.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/urls.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/uuid7.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_internal/websockets.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_launchers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_result_records.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/fetcher.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/generator.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/models.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/naming.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/renderer.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/schema_converter.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/templates/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/templates/sdk.py.jinja +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/types.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_sdk/unions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_states.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_vendor/croniter/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_vendor/croniter/croniter.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_versioning.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/_waiters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/agent.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/analytics/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/artifacts.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/assets/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/assets/core.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/assets/materialize.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/automations.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/abstract.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/core.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/fields.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/notifications.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/redis.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/system.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/blocks/webhook.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/_file_collector.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/_ignore_filter.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/_path_resolver.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/_zip_builder.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/_zip_extractor.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/bundles/execute.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/cache_policies.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/_version_checking.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/attribution.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/cloud.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/collections.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/constants.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_artifacts/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_artifacts/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_automations/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_automations/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_documents/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_schemas/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_types/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_blocks_types/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_concurrency_limits/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_deployments/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_deployments/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_events/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_events/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_flow_runs/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_flow_runs/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_flows/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_flows/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_logs/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_logs/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_variables/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_variables/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_work_pools/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/_work_pools/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/orchestration/routes.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/actions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/filters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/objects.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/responses.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/schedules.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/schemas/sorting.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/subscriptions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/types/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/types/flexible_schedule_list.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/client/utilities.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/_asyncio.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/_events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/_leases.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/_sync.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/asyncio.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/context.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/services.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/sync.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/_asyncio.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/_events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/asyncio.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/context.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/services.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/concurrency/v1/sync.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/deployments.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/flow_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/runner.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/schedules.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/steps/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/steps/core.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/steps/pull.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/deployments/steps/utility.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/docker/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/docker/_buildx.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/docker/docker_image.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/engine.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/actions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/clients.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/filters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/related.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/schemas/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/schemas/automations.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/schemas/deployment_triggers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/schemas/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/schemas/labelling.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/subscribers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/utilities.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/events/worker.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/exceptions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/filesystems.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/flows.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/cloud_run.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/coiled.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/container_instance.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/ecs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/infrastructure/provisioners/modal.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/input/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/input/actions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/input/run_input.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/locking/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/locking/_filelock.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/locking/filesystem.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/locking/memory.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/locking/protocol.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/clients.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/configuration.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/filters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/formatters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/handlers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/highlighters.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/logging/logging.yml +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/main.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/plugins.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/py.typed +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/results.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_cancel_finalizer.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_control_channel.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_event_emitter.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_flow_resolver.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_flow_run_executor.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_hook_runner.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_limit_manager.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_process_manager.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_scheduled_run_poller.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_state_proposer.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/_workspace_resolver.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/server.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runner/storage.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runtime/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runtime/deployment.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runtime/flow_run.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/runtime/task_run.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/schedules.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/serializers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/admin.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/artifacts.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/automations.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/background_workers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/block_capabilities.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/block_documents.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/block_schemas.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/block_types.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/clients.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/collections.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/collections_data/views/aggregate-worker-metadata.json +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/concurrency_limits.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/concurrency_limits_v2.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/csrf_token.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/dependencies.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/deployments.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/flow_run_states.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/flow_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/flows.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/logs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/middleware.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/root.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/run_history.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/saved_searches.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/server.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/static/prefect-logo-mark-gradient.png +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/task_run_states.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/task_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/task_workers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/templates.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/ui/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/ui/flow_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/ui/flows.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/ui/schemas.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/ui/task_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/validation.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/variables.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/work_queues.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/server/api/workers.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/constants.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/context.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/legacy.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/_defaults.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/api.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/cli.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/client.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/cloud.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/deployments.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/experiments.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/flows.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/internal.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/logging.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/plugins.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/results.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/root.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/runner.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/api.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/concurrency.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/database.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/deployments.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/docket.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/ephemeral.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/events.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/flow_run_graph.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/logs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/root.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/services.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/tasks.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/server/ui.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/tasks.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/telemetry.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/testing.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/models/worker.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/profiles.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/profiles.toml +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/settings/sources.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/states.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/task_runs.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/task_worker.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/telemetry/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/telemetry/_metrics.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/telemetry/run_telemetry.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/transactions.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/_concurrency.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/_datetime.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/_schema.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/entrypoint.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/types/names.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/_ast.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/_deprecated.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/_engine.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/_git.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/_infrastructure_exit_codes.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/annotations.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/asyncutils/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/asyncutils/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/callables/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/callables/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/collections.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/compat.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/context.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/dispatch.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/dockerutils.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/engine/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/engine/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/filesystem/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/filesystem/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/generics.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/hashing.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/importtools.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/math.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/names.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/pydantic.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/render_swagger.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/schema_tools/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/schema_tools/hydration.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/schema_tools/validation.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/services.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/slugify.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/templating/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/templating/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/text.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/timeout.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/urls.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/utilities/visualization.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/variables.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/AGENTS.md +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/__init__.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/base.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/block.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/cloud.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/process.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/server.py +0 -0
- {prefect_client-3.7.1.dev2 → prefect_client-3.7.1.dev3}/src/prefect/workers/utilities.py +0 -0
|
@@ -31,6 +31,7 @@ There is no formal public/private boundary beyond the `_` prefix convention. Mod
|
|
|
31
31
|
- **`ThreadPoolTaskRunner` is cloudpickled when a flow run is dispatched to a subprocess.** `threading.Lock` and other non-picklable thread primitives must be dropped in `__getstate__` and rebuilt in `__setstate__`. Any new instance state added to this class must be evaluated for picklability.
|
|
32
32
|
- **Nested task submissions on a bounded `ThreadPoolTaskRunner` can deadlock.** When a worker task submits children and blocks on `.result()` while all `max_workers` threads are busy, the pool starves. `_warn_if_nested_submit_would_deadlock` detects this and emits a one-time warning — preserve this detection when changing pool management.
|
|
33
33
|
- **`ResultRecordMetadata` tolerates unknown serializer types.** When loading persisted metadata, an unrecognized serializer `type` is converted to an `UnknownSerializer` placeholder rather than raising `ValidationError`. This allows inspecting result metadata when the serializer implementation is unavailable in the current environment. However, known serializer types with invalid fields still raise `ValidationError`. `UnknownSerializer.dumps()` and `UnknownSerializer.loads()` raise `RuntimeError` — the tolerance is for inspection only, not actual serialization/deserialization.
|
|
34
|
+
- **Flow-run suspension is enforced at orchestration boundaries.** Suspension is delivered via `FlowRunSuspensionRequest` and raised with `raise_if_flow_run_suspension_requested()`. When changing engines, futures, task runners, or generator execution, check before returning control to flow user code or proposing a flow state that could leave `Suspended`; keep sync/async paths aligned and avoid per-boundary API reads.
|
|
34
35
|
|
|
35
36
|
## Logging
|
|
36
37
|
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import contextvars
|
|
5
|
+
import threading
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from typing import Generator
|
|
8
|
+
from uuid import UUID
|
|
9
|
+
|
|
10
|
+
from prefect.client.schemas.objects import State
|
|
11
|
+
from prefect.exceptions import Pause
|
|
12
|
+
from prefect.logging.loggers import get_logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FlowRunSuspensionRequest:
|
|
16
|
+
"""
|
|
17
|
+
Mutable in-process suspension request shared by flow, child flow, and task contexts.
|
|
18
|
+
|
|
19
|
+
The stored state is the server-accepted `Suspended` state that should be raised
|
|
20
|
+
through Prefect's existing `Pause` control-flow path at the next orchestration
|
|
21
|
+
boundary.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._suspended_state: State | None = None
|
|
26
|
+
self._lock = threading.Lock()
|
|
27
|
+
|
|
28
|
+
def mark_requested(self, state: State) -> None:
|
|
29
|
+
with self._lock:
|
|
30
|
+
self._suspended_state = state
|
|
31
|
+
|
|
32
|
+
def get_state(self) -> State | None:
|
|
33
|
+
with self._lock:
|
|
34
|
+
return self._suspended_state
|
|
35
|
+
|
|
36
|
+
def is_requested(self) -> bool:
|
|
37
|
+
return self.get_state() is not None
|
|
38
|
+
|
|
39
|
+
def raise_if_requested(self) -> None:
|
|
40
|
+
if state := self.get_state():
|
|
41
|
+
raise Pause(state=state)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def is_suspended_flow_run_state(state: State | None) -> bool:
|
|
45
|
+
return bool(state and state.is_paused() and state.name == "Suspended")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
_active_flow_run_suspension_requests: dict[UUID, FlowRunSuspensionRequest] = {}
|
|
49
|
+
_active_flow_run_suspension_requests_lock = threading.Lock()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@contextmanager
|
|
53
|
+
def register_flow_run_suspension_request(
|
|
54
|
+
flow_run_id: UUID,
|
|
55
|
+
suspension_request: FlowRunSuspensionRequest,
|
|
56
|
+
) -> Generator[None, None, None]:
|
|
57
|
+
with _active_flow_run_suspension_requests_lock:
|
|
58
|
+
_active_flow_run_suspension_requests[flow_run_id] = suspension_request
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
yield
|
|
62
|
+
finally:
|
|
63
|
+
with _active_flow_run_suspension_requests_lock:
|
|
64
|
+
if (
|
|
65
|
+
_active_flow_run_suspension_requests.get(flow_run_id)
|
|
66
|
+
is suspension_request
|
|
67
|
+
):
|
|
68
|
+
_active_flow_run_suspension_requests.pop(flow_run_id, None)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def mark_flow_run_suspension_requested(flow_run_id: UUID, state: State) -> bool:
|
|
72
|
+
with _active_flow_run_suspension_requests_lock:
|
|
73
|
+
suspension_request = _active_flow_run_suspension_requests.get(flow_run_id)
|
|
74
|
+
|
|
75
|
+
if suspension_request is None:
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
suspension_request.mark_requested(state)
|
|
79
|
+
return True
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def raise_if_flow_run_suspension_requested() -> None:
|
|
83
|
+
from prefect.context import FlowRunContext
|
|
84
|
+
|
|
85
|
+
if flow_run_context := FlowRunContext.get():
|
|
86
|
+
flow_run_context.flow_run_suspension_request.raise_if_requested()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@contextmanager
|
|
90
|
+
def observe_flow_run_suspension(
|
|
91
|
+
flow_run_id: UUID,
|
|
92
|
+
suspension_request: FlowRunSuspensionRequest,
|
|
93
|
+
polling_interval: float = 10,
|
|
94
|
+
) -> Generator[None, None, None]:
|
|
95
|
+
from prefect._observers import FlowRunSuspendingObserver
|
|
96
|
+
|
|
97
|
+
logger = get_logger("flow_run_suspension")
|
|
98
|
+
stop_event = threading.Event()
|
|
99
|
+
ready_event = threading.Event()
|
|
100
|
+
|
|
101
|
+
def mark_suspended(flow_run_id: UUID, state: State) -> None:
|
|
102
|
+
if not mark_flow_run_suspension_requested(flow_run_id, state):
|
|
103
|
+
suspension_request.mark_requested(state)
|
|
104
|
+
|
|
105
|
+
async def run_observer() -> None:
|
|
106
|
+
async with FlowRunSuspendingObserver(
|
|
107
|
+
on_suspended=mark_suspended,
|
|
108
|
+
polling_interval=polling_interval,
|
|
109
|
+
) as observer:
|
|
110
|
+
await observer.watch_flow_run_id(flow_run_id)
|
|
111
|
+
ready_event.set()
|
|
112
|
+
while not stop_event.is_set():
|
|
113
|
+
await asyncio.sleep(0.2)
|
|
114
|
+
|
|
115
|
+
context = contextvars.copy_context()
|
|
116
|
+
|
|
117
|
+
def observer_thread() -> None:
|
|
118
|
+
try:
|
|
119
|
+
context.run(lambda: asyncio.run(run_observer()))
|
|
120
|
+
except Exception:
|
|
121
|
+
logger.debug(
|
|
122
|
+
"Flow run suspension observer exited with an exception",
|
|
123
|
+
exc_info=True,
|
|
124
|
+
)
|
|
125
|
+
finally:
|
|
126
|
+
ready_event.set()
|
|
127
|
+
|
|
128
|
+
thread = threading.Thread(target=observer_thread, daemon=True)
|
|
129
|
+
thread.start()
|
|
130
|
+
ready_event.wait()
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
yield
|
|
134
|
+
finally:
|
|
135
|
+
stop_event.set()
|
|
136
|
+
thread.join(timeout=2)
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import uuid
|
|
5
|
+
from contextlib import AsyncExitStack
|
|
6
|
+
from typing import Any, Protocol
|
|
7
|
+
|
|
8
|
+
from prefect._flow_run_suspension import is_suspended_flow_run_state
|
|
9
|
+
from prefect.client.orchestration import PrefectClient, get_client
|
|
10
|
+
from prefect.client.schemas.filters import (
|
|
11
|
+
FlowRunFilter,
|
|
12
|
+
FlowRunFilterId,
|
|
13
|
+
FlowRunFilterState,
|
|
14
|
+
FlowRunFilterStateName,
|
|
15
|
+
FlowRunFilterStateType,
|
|
16
|
+
)
|
|
17
|
+
from prefect.client.schemas.objects import State, StateType
|
|
18
|
+
from prefect.events.clients import PrefectEventSubscriber, get_events_subscriber
|
|
19
|
+
from prefect.events.filters import EventFilter, EventNameFilter
|
|
20
|
+
from prefect.logging.loggers import get_logger
|
|
21
|
+
from prefect.utilities.services import critical_service_loop
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OnCancellingCallback(Protocol):
|
|
25
|
+
def __call__(self, flow_run_id: uuid.UUID) -> None: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class OnSuspendedCallback(Protocol):
|
|
29
|
+
def __call__(self, flow_run_id: uuid.UUID, state: State) -> None: ...
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class OnFailureCallback(Protocol):
|
|
33
|
+
def __call__(self, flow_run_ids: set[uuid.UUID]) -> None: ...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FlowRunCancellingObserver:
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
on_cancelling: OnCancellingCallback,
|
|
40
|
+
polling_interval: float = 10,
|
|
41
|
+
event_filter: EventFilter | None = None,
|
|
42
|
+
on_failure: OnFailureCallback | None = None,
|
|
43
|
+
):
|
|
44
|
+
"""
|
|
45
|
+
Observer that cancels flow runs when they are marked as cancelling.
|
|
46
|
+
|
|
47
|
+
Will use a websocket connection to listen for cancelling flow run events by default with a fallback
|
|
48
|
+
to polling when the websocket connection is lost.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
on_cancelling: Callback to call when a flow run is marked as cancelling.
|
|
52
|
+
polling_interval: Interval in seconds to poll for cancelling flow runs when websocket connection is lost.
|
|
53
|
+
event_filter: Optional event filter to use for the websocket subscription.
|
|
54
|
+
If not provided, defaults to filtering for "prefect.flow-run.Cancelling" events.
|
|
55
|
+
on_failure: Optional callback to call when both websocket and polling mechanisms fail.
|
|
56
|
+
Called with the set of in-flight flow run IDs that can no longer be monitored for cancellation.
|
|
57
|
+
"""
|
|
58
|
+
self.logger = get_logger("FlowRunCancellingObserver")
|
|
59
|
+
self.on_cancelling = on_cancelling
|
|
60
|
+
self.on_failure = on_failure
|
|
61
|
+
self.polling_interval = polling_interval
|
|
62
|
+
|
|
63
|
+
if event_filter is not None:
|
|
64
|
+
if (
|
|
65
|
+
event_filter.event is None
|
|
66
|
+
or event_filter.event.name is None
|
|
67
|
+
or "prefect.flow-run.Cancelling" not in event_filter.event.name
|
|
68
|
+
):
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"event_filter must include 'prefect.flow-run.Cancelling' in event.name"
|
|
71
|
+
)
|
|
72
|
+
self._event_filter = event_filter
|
|
73
|
+
else:
|
|
74
|
+
self._event_filter = EventFilter(
|
|
75
|
+
event=EventNameFilter(name=["prefect.flow-run.Cancelling"])
|
|
76
|
+
)
|
|
77
|
+
self._in_flight_flow_run_ids: set[uuid.UUID] = set()
|
|
78
|
+
self._events_subscriber: PrefectEventSubscriber | None
|
|
79
|
+
self._exit_stack = AsyncExitStack()
|
|
80
|
+
self._consumer_task: asyncio.Task[None] | None = None
|
|
81
|
+
self._polling_task: asyncio.Task[None] | None = None
|
|
82
|
+
self._is_shutting_down = False
|
|
83
|
+
self._client: PrefectClient | None = None
|
|
84
|
+
self._cancelling_flow_run_ids: set[uuid.UUID] = set()
|
|
85
|
+
|
|
86
|
+
def add_in_flight_flow_run_id(self, flow_run_id: uuid.UUID):
|
|
87
|
+
self.logger.debug("Adding in-flight flow run ID: %s", flow_run_id)
|
|
88
|
+
self._in_flight_flow_run_ids.add(flow_run_id)
|
|
89
|
+
|
|
90
|
+
def remove_in_flight_flow_run_id(self, flow_run_id: uuid.UUID):
|
|
91
|
+
self.logger.debug("Removing in-flight flow run ID: %s", flow_run_id)
|
|
92
|
+
self._in_flight_flow_run_ids.discard(flow_run_id)
|
|
93
|
+
self._cancelling_flow_run_ids.discard(flow_run_id)
|
|
94
|
+
|
|
95
|
+
async def _consume_events(self):
|
|
96
|
+
if self._events_subscriber is None:
|
|
97
|
+
raise RuntimeError(
|
|
98
|
+
"Events subscriber not initialized. Please use `async with` to initialize the observer."
|
|
99
|
+
)
|
|
100
|
+
async for event in self._events_subscriber:
|
|
101
|
+
try:
|
|
102
|
+
flow_run_id = uuid.UUID(
|
|
103
|
+
event.resource["prefect.resource.id"].replace(
|
|
104
|
+
"prefect.flow-run.", ""
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
if flow_run_id not in self._in_flight_flow_run_ids:
|
|
108
|
+
continue
|
|
109
|
+
self.on_cancelling(flow_run_id)
|
|
110
|
+
except ValueError:
|
|
111
|
+
self.logger.warning(
|
|
112
|
+
"Received event with invalid flow run ID: %s",
|
|
113
|
+
event.resource["prefect.resource.id"],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def _start_polling_task(self, task: asyncio.Task[None]):
|
|
117
|
+
if task.cancelled():
|
|
118
|
+
# If the consumer task was cancelled, the observer is shutting down
|
|
119
|
+
# and we don't need to start the polling task
|
|
120
|
+
return
|
|
121
|
+
if exc := task.exception():
|
|
122
|
+
self.logger.warning(
|
|
123
|
+
"The FlowRunCancellingObserver websocket failed with an exception. Switching to polling mode.",
|
|
124
|
+
exc_info=exc,
|
|
125
|
+
)
|
|
126
|
+
self._polling_task = asyncio.create_task(
|
|
127
|
+
critical_service_loop(
|
|
128
|
+
workload=self._check_for_cancelled_flow_runs,
|
|
129
|
+
interval=self.polling_interval,
|
|
130
|
+
jitter_range=0.3,
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
self._polling_task.add_done_callback(self._handle_polling_task_done)
|
|
134
|
+
|
|
135
|
+
def _handle_polling_task_done(self, task: asyncio.Task[None]):
|
|
136
|
+
if task.exception():
|
|
137
|
+
self.logger.error(
|
|
138
|
+
"Cancellation polling task failed. Execution will continue, but flow run cancellation will fail.",
|
|
139
|
+
exc_info=task.exception(),
|
|
140
|
+
)
|
|
141
|
+
if self.on_failure is not None:
|
|
142
|
+
self.on_failure(self._in_flight_flow_run_ids.copy())
|
|
143
|
+
else:
|
|
144
|
+
self.logger.debug("Polling task completed")
|
|
145
|
+
|
|
146
|
+
async def _check_for_cancelled_flow_runs(self):
|
|
147
|
+
if self._is_shutting_down:
|
|
148
|
+
return
|
|
149
|
+
if self._client is None:
|
|
150
|
+
raise RuntimeError(
|
|
151
|
+
"Client not initialized. Please use `async with` to initialize the observer."
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
self.logger.debug("Checking for cancelled flow runs")
|
|
155
|
+
named_cancelling_flow_runs = await self._client.read_flow_runs(
|
|
156
|
+
flow_run_filter=FlowRunFilter(
|
|
157
|
+
state=FlowRunFilterState(
|
|
158
|
+
type=FlowRunFilterStateType(any_=[StateType.CANCELLED]),
|
|
159
|
+
name=FlowRunFilterStateName(any_=["Cancelling"]),
|
|
160
|
+
),
|
|
161
|
+
# Avoid duplicate cancellation calls
|
|
162
|
+
id=FlowRunFilterId(
|
|
163
|
+
any_=list(
|
|
164
|
+
self._in_flight_flow_run_ids - self._cancelling_flow_run_ids
|
|
165
|
+
)
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
typed_cancelling_flow_runs = await self._client.read_flow_runs(
|
|
171
|
+
flow_run_filter=FlowRunFilter(
|
|
172
|
+
state=FlowRunFilterState(
|
|
173
|
+
type=FlowRunFilterStateType(any_=[StateType.CANCELLING]),
|
|
174
|
+
),
|
|
175
|
+
# Avoid duplicate cancellation calls
|
|
176
|
+
id=FlowRunFilterId(
|
|
177
|
+
any_=list(
|
|
178
|
+
self._in_flight_flow_run_ids - self._cancelling_flow_run_ids
|
|
179
|
+
)
|
|
180
|
+
),
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
cancelling_flow_runs = named_cancelling_flow_runs + typed_cancelling_flow_runs
|
|
185
|
+
|
|
186
|
+
if cancelling_flow_runs:
|
|
187
|
+
self.logger.info(
|
|
188
|
+
"Found %s flow runs awaiting cancellation.", len(cancelling_flow_runs)
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
for flow_run in cancelling_flow_runs:
|
|
192
|
+
self._cancelling_flow_run_ids.add(flow_run.id)
|
|
193
|
+
self.on_cancelling(flow_run.id)
|
|
194
|
+
|
|
195
|
+
async def __aenter__(self):
|
|
196
|
+
try:
|
|
197
|
+
self._events_subscriber = await self._exit_stack.enter_async_context(
|
|
198
|
+
get_events_subscriber(filter=self._event_filter)
|
|
199
|
+
)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self.logger.warning(
|
|
202
|
+
"Failed to connect to the events stream. Falling back to polling "
|
|
203
|
+
"for cancellation events. Reason: %s",
|
|
204
|
+
str(e),
|
|
205
|
+
)
|
|
206
|
+
self._events_subscriber = None
|
|
207
|
+
|
|
208
|
+
self._client = await self._exit_stack.enter_async_context(get_client())
|
|
209
|
+
|
|
210
|
+
if self._events_subscriber is not None:
|
|
211
|
+
self._consumer_task = asyncio.create_task(self._consume_events())
|
|
212
|
+
self._consumer_task.add_done_callback(self._start_polling_task)
|
|
213
|
+
else:
|
|
214
|
+
# WebSocket unavailable — start polling immediately
|
|
215
|
+
self._polling_task = asyncio.create_task(
|
|
216
|
+
critical_service_loop(
|
|
217
|
+
workload=self._check_for_cancelled_flow_runs,
|
|
218
|
+
interval=self.polling_interval,
|
|
219
|
+
jitter_range=0.3,
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
self._polling_task.add_done_callback(self._handle_polling_task_done)
|
|
223
|
+
|
|
224
|
+
return self
|
|
225
|
+
|
|
226
|
+
async def __aexit__(self, *exc_info: Any):
|
|
227
|
+
self.logger.debug("Shutting down FlowRunCancellingObserver")
|
|
228
|
+
self._is_shutting_down = True
|
|
229
|
+
await self._exit_stack.__aexit__(*exc_info)
|
|
230
|
+
if self._consumer_task is not None:
|
|
231
|
+
self._consumer_task.cancel()
|
|
232
|
+
try:
|
|
233
|
+
await self._consumer_task
|
|
234
|
+
except asyncio.CancelledError:
|
|
235
|
+
pass
|
|
236
|
+
except Exception:
|
|
237
|
+
self.logger.warning(
|
|
238
|
+
"Consumer task exited with exception", exc_info=True
|
|
239
|
+
)
|
|
240
|
+
pass
|
|
241
|
+
|
|
242
|
+
if self._polling_task is not None:
|
|
243
|
+
self._polling_task.cancel()
|
|
244
|
+
try:
|
|
245
|
+
await self._polling_task
|
|
246
|
+
except asyncio.CancelledError:
|
|
247
|
+
pass
|
|
248
|
+
except Exception:
|
|
249
|
+
self.logger.warning("Polling task exited with exception", exc_info=True)
|
|
250
|
+
pass
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class FlowRunSuspendingObserver:
|
|
254
|
+
def __init__(
|
|
255
|
+
self,
|
|
256
|
+
on_suspended: OnSuspendedCallback,
|
|
257
|
+
polling_interval: float = 10,
|
|
258
|
+
event_filter: EventFilter | None = None,
|
|
259
|
+
on_failure: OnFailureCallback | None = None,
|
|
260
|
+
):
|
|
261
|
+
"""
|
|
262
|
+
Observer that notices flow runs when they are marked as suspended.
|
|
263
|
+
|
|
264
|
+
Uses the events stream to listen for suspension events by default, with a
|
|
265
|
+
polling fallback when the websocket connection is unavailable or lost.
|
|
266
|
+
"""
|
|
267
|
+
self.logger = get_logger("FlowRunSuspendingObserver")
|
|
268
|
+
self.on_suspended = on_suspended
|
|
269
|
+
self.on_failure = on_failure
|
|
270
|
+
self.polling_interval = polling_interval
|
|
271
|
+
|
|
272
|
+
if event_filter is not None:
|
|
273
|
+
if (
|
|
274
|
+
event_filter.event is None
|
|
275
|
+
or event_filter.event.name is None
|
|
276
|
+
or "prefect.flow-run.Suspended" not in event_filter.event.name
|
|
277
|
+
):
|
|
278
|
+
raise ValueError(
|
|
279
|
+
"event_filter must include 'prefect.flow-run.Suspended' in event.name"
|
|
280
|
+
)
|
|
281
|
+
self._event_filter = event_filter
|
|
282
|
+
else:
|
|
283
|
+
self._event_filter = EventFilter(
|
|
284
|
+
event=EventNameFilter(name=["prefect.flow-run.Suspended"])
|
|
285
|
+
)
|
|
286
|
+
self._in_flight_flow_run_ids: set[uuid.UUID] = set()
|
|
287
|
+
self._events_subscriber: PrefectEventSubscriber | None
|
|
288
|
+
self._exit_stack = AsyncExitStack()
|
|
289
|
+
self._consumer_task: asyncio.Task[None] | None = None
|
|
290
|
+
self._polling_task: asyncio.Task[None] | None = None
|
|
291
|
+
self._is_shutting_down = False
|
|
292
|
+
self._client: PrefectClient | None = None
|
|
293
|
+
self._suspended_flow_run_ids: set[uuid.UUID] = set()
|
|
294
|
+
|
|
295
|
+
def add_in_flight_flow_run_id(self, flow_run_id: uuid.UUID):
|
|
296
|
+
self.logger.debug("Adding in-flight flow run ID: %s", flow_run_id)
|
|
297
|
+
self._in_flight_flow_run_ids.add(flow_run_id)
|
|
298
|
+
|
|
299
|
+
def remove_in_flight_flow_run_id(self, flow_run_id: uuid.UUID):
|
|
300
|
+
self.logger.debug("Removing in-flight flow run ID: %s", flow_run_id)
|
|
301
|
+
self._in_flight_flow_run_ids.discard(flow_run_id)
|
|
302
|
+
self._suspended_flow_run_ids.discard(flow_run_id)
|
|
303
|
+
|
|
304
|
+
async def watch_flow_run_id(self, flow_run_id: uuid.UUID) -> None:
|
|
305
|
+
self.add_in_flight_flow_run_id(flow_run_id)
|
|
306
|
+
if self._client is None:
|
|
307
|
+
raise RuntimeError(
|
|
308
|
+
"Client not initialized. Please use `async with` to initialize the observer."
|
|
309
|
+
)
|
|
310
|
+
retry_interval = max(min(self.polling_interval, 1.0), 0.01)
|
|
311
|
+
attempts = 0
|
|
312
|
+
|
|
313
|
+
while not self._is_shutting_down:
|
|
314
|
+
if flow_run_id in self._suspended_flow_run_ids:
|
|
315
|
+
return
|
|
316
|
+
|
|
317
|
+
try:
|
|
318
|
+
flow_run = await self._client.read_flow_run(flow_run_id)
|
|
319
|
+
except Exception:
|
|
320
|
+
attempts += 1
|
|
321
|
+
log = self.logger.warning if attempts == 1 else self.logger.debug
|
|
322
|
+
log(
|
|
323
|
+
"Failed to check current state for flow run %s while starting"
|
|
324
|
+
" suspension observer. Retrying before reporting observer ready.",
|
|
325
|
+
flow_run_id,
|
|
326
|
+
exc_info=True,
|
|
327
|
+
)
|
|
328
|
+
await asyncio.sleep(retry_interval)
|
|
329
|
+
continue
|
|
330
|
+
|
|
331
|
+
self._notify_if_suspended_state(flow_run_id, flow_run.state)
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
def _notify_if_suspended_state(
|
|
335
|
+
self, flow_run_id: uuid.UUID, state: State | None
|
|
336
|
+
) -> None:
|
|
337
|
+
if state is not None and is_suspended_flow_run_state(state):
|
|
338
|
+
self._suspended_flow_run_ids.add(flow_run_id)
|
|
339
|
+
self.on_suspended(flow_run_id, state)
|
|
340
|
+
|
|
341
|
+
async def _notify_if_suspended(self, flow_run_id: uuid.UUID) -> None:
|
|
342
|
+
if self._client is None:
|
|
343
|
+
raise RuntimeError(
|
|
344
|
+
"Client not initialized. Please use `async with` to initialize the observer."
|
|
345
|
+
)
|
|
346
|
+
if flow_run_id in self._suspended_flow_run_ids:
|
|
347
|
+
return
|
|
348
|
+
|
|
349
|
+
flow_run = await self._client.read_flow_run(flow_run_id)
|
|
350
|
+
self._notify_if_suspended_state(flow_run_id, flow_run.state)
|
|
351
|
+
|
|
352
|
+
async def _consume_events(self):
|
|
353
|
+
if self._events_subscriber is None:
|
|
354
|
+
raise RuntimeError(
|
|
355
|
+
"Events subscriber not initialized. Please use `async with` to initialize the observer."
|
|
356
|
+
)
|
|
357
|
+
async for event in self._events_subscriber:
|
|
358
|
+
try:
|
|
359
|
+
flow_run_id = uuid.UUID(
|
|
360
|
+
event.resource["prefect.resource.id"].replace(
|
|
361
|
+
"prefect.flow-run.", ""
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
if flow_run_id not in self._in_flight_flow_run_ids:
|
|
365
|
+
continue
|
|
366
|
+
await self._notify_if_suspended(flow_run_id)
|
|
367
|
+
except ValueError:
|
|
368
|
+
self.logger.warning(
|
|
369
|
+
"Received event with invalid flow run ID: %s",
|
|
370
|
+
event.resource["prefect.resource.id"],
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
def _start_polling_task(self, task: asyncio.Task[None]):
|
|
374
|
+
if task.cancelled() or self._is_shutting_down:
|
|
375
|
+
return
|
|
376
|
+
|
|
377
|
+
if exc := task.exception():
|
|
378
|
+
self.logger.warning(
|
|
379
|
+
"The FlowRunSuspendingObserver websocket failed with an exception. Switching to polling mode.",
|
|
380
|
+
exc_info=exc,
|
|
381
|
+
)
|
|
382
|
+
else:
|
|
383
|
+
self.logger.warning(
|
|
384
|
+
"The FlowRunSuspendingObserver websocket closed. Switching to polling mode.",
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
self._polling_task = asyncio.create_task(
|
|
388
|
+
critical_service_loop(
|
|
389
|
+
workload=self._check_for_suspended_flow_runs,
|
|
390
|
+
interval=self.polling_interval,
|
|
391
|
+
jitter_range=0.3,
|
|
392
|
+
)
|
|
393
|
+
)
|
|
394
|
+
self._polling_task.add_done_callback(self._handle_polling_task_done)
|
|
395
|
+
|
|
396
|
+
def _handle_polling_task_done(self, task: asyncio.Task[None]):
|
|
397
|
+
if task.exception():
|
|
398
|
+
self.logger.error(
|
|
399
|
+
"Suspension polling task failed. Execution will continue, but external flow run suspension will fail.",
|
|
400
|
+
exc_info=task.exception(),
|
|
401
|
+
)
|
|
402
|
+
if self.on_failure is not None:
|
|
403
|
+
self.on_failure(self._in_flight_flow_run_ids.copy())
|
|
404
|
+
else:
|
|
405
|
+
self.logger.debug("Polling task completed")
|
|
406
|
+
|
|
407
|
+
async def _check_for_suspended_flow_runs(self):
|
|
408
|
+
if self._is_shutting_down:
|
|
409
|
+
return
|
|
410
|
+
if self._client is None:
|
|
411
|
+
raise RuntimeError(
|
|
412
|
+
"Client not initialized. Please use `async with` to initialize the observer."
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
flow_run_ids = self._in_flight_flow_run_ids - self._suspended_flow_run_ids
|
|
416
|
+
if not flow_run_ids:
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
self.logger.debug("Checking for suspended flow runs")
|
|
420
|
+
suspended_flow_runs = await self._client.read_flow_runs(
|
|
421
|
+
flow_run_filter=FlowRunFilter(
|
|
422
|
+
state=FlowRunFilterState(
|
|
423
|
+
type=FlowRunFilterStateType(any_=[StateType.PAUSED]),
|
|
424
|
+
name=FlowRunFilterStateName(any_=["Suspended"]),
|
|
425
|
+
),
|
|
426
|
+
id=FlowRunFilterId(any_=list(flow_run_ids)),
|
|
427
|
+
),
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
if suspended_flow_runs:
|
|
431
|
+
self.logger.info(
|
|
432
|
+
"Found %s flow runs awaiting suspension.", len(suspended_flow_runs)
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
for flow_run in suspended_flow_runs:
|
|
436
|
+
if flow_run.state:
|
|
437
|
+
self._suspended_flow_run_ids.add(flow_run.id)
|
|
438
|
+
self.on_suspended(flow_run.id, flow_run.state)
|
|
439
|
+
|
|
440
|
+
async def __aenter__(self):
|
|
441
|
+
try:
|
|
442
|
+
self._events_subscriber = await self._exit_stack.enter_async_context(
|
|
443
|
+
get_events_subscriber(filter=self._event_filter)
|
|
444
|
+
)
|
|
445
|
+
except Exception as e:
|
|
446
|
+
self.logger.warning(
|
|
447
|
+
"Failed to connect to the events stream. Falling back to polling "
|
|
448
|
+
"for suspension events. Reason: %s",
|
|
449
|
+
str(e),
|
|
450
|
+
)
|
|
451
|
+
self._events_subscriber = None
|
|
452
|
+
|
|
453
|
+
self._client = await self._exit_stack.enter_async_context(get_client())
|
|
454
|
+
|
|
455
|
+
if self._events_subscriber is not None:
|
|
456
|
+
self._consumer_task = asyncio.create_task(self._consume_events())
|
|
457
|
+
self._consumer_task.add_done_callback(self._start_polling_task)
|
|
458
|
+
else:
|
|
459
|
+
self._polling_task = asyncio.create_task(
|
|
460
|
+
critical_service_loop(
|
|
461
|
+
workload=self._check_for_suspended_flow_runs,
|
|
462
|
+
interval=self.polling_interval,
|
|
463
|
+
jitter_range=0.3,
|
|
464
|
+
)
|
|
465
|
+
)
|
|
466
|
+
self._polling_task.add_done_callback(self._handle_polling_task_done)
|
|
467
|
+
|
|
468
|
+
return self
|
|
469
|
+
|
|
470
|
+
async def __aexit__(self, *exc_info: Any):
|
|
471
|
+
self.logger.debug("Shutting down FlowRunSuspendingObserver")
|
|
472
|
+
self._is_shutting_down = True
|
|
473
|
+
await self._exit_stack.__aexit__(*exc_info)
|
|
474
|
+
if self._consumer_task is not None:
|
|
475
|
+
self._consumer_task.cancel()
|
|
476
|
+
try:
|
|
477
|
+
await self._consumer_task
|
|
478
|
+
except asyncio.CancelledError:
|
|
479
|
+
pass
|
|
480
|
+
except Exception:
|
|
481
|
+
self.logger.warning(
|
|
482
|
+
"Consumer task exited with exception", exc_info=True
|
|
483
|
+
)
|
|
484
|
+
pass
|
|
485
|
+
|
|
486
|
+
if self._polling_task is not None:
|
|
487
|
+
self._polling_task.cancel()
|
|
488
|
+
try:
|
|
489
|
+
await self._polling_task
|
|
490
|
+
except asyncio.CancelledError:
|
|
491
|
+
pass
|
|
492
|
+
except Exception:
|
|
493
|
+
self.logger.warning("Polling task exited with exception", exc_info=True)
|
|
494
|
+
pass
|
|
@@ -539,7 +539,7 @@ def _extract_and_run_flow(
|
|
|
539
539
|
env: The environment to use when running the flow.
|
|
540
540
|
"""
|
|
541
541
|
|
|
542
|
-
os.environ.update(sanitize_subprocess_env(env))
|
|
542
|
+
os.environ.update(sanitize_subprocess_env(env, remove_from=os.environ))
|
|
543
543
|
# TODO: make this a thing we can pass directly to the engine
|
|
544
544
|
os.environ["PREFECT__ENABLE_CANCELLATION_AND_CRASHED_HOOKS"] = "false"
|
|
545
545
|
settings_context = get_settings_context()
|
|
@@ -10,6 +10,7 @@ HTTP client for communicating with Prefect server and Prefect Cloud.
|
|
|
10
10
|
- **Client schemas are separate from server schemas.** This module has its own `schemas/` to avoid tangling with `server/schemas/`. Keep the boundary clean.
|
|
11
11
|
- **Do not import server-only modules** (`server/database`, `server/models`, etc.) from anything in this directory — it would break the `prefect-client` package build.
|
|
12
12
|
- **Task-run submission schemas must be eagerly rebuilt.** Schemas instantiated on the concurrent submission path (`Task.create_local_run()`) are rebuilt at import time via `model_rebuild()` at the bottom of `schemas/objects.py`. Pydantic defers schema construction to first use; under threadpool contention, multiple workers race to build the same schema simultaneously. If you add a new schema used in this hot path, add a corresponding `model_rebuild()` call there.
|
|
13
|
+
- **`schemas/worker_channel.py` is a versioned cross-system protocol contract.** It defines the `work_pool_worker_channel.v1` WebSocket handshake shared between workers and server — both sides must stay in sync. `WorkerChannelAuthRequest`/`WorkerChannelAuthSuccess` are pre-handshake and deliberately excluded from the `WorkerChannelApplicationFrame` union; `validate_worker_channel_frame()` will reject them. All frame models use `extra="forbid"`, so adding a new field to an existing frame requires a new version string, not just a field addition. Cloud authorization details are intentionally excluded from this shared contract.
|
|
13
14
|
|
|
14
15
|
## Structure
|
|
15
16
|
|