-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
Background
Related to #18837
Users are increasingly adopting uv for dependency management, but Prefect's current execution environment setup makes it difficult to use uv effectively. The core issue is an ordering problem: Prefect needs flow code and configuration present before creating a process for flow execution.
Current workaround: Users run uv sync in pull steps after code is pulled, but this is fragile and dependent on uv configuration, potentially breaking if uv creates different virtual environments.
User desire: Be able to use uv run to execute their flows, with all dependency information defined in pyproject.toml, aligning with the Python ecosystem's standardization around pyproject.toml.
Proposed Solution
This enhancement proposes four key architectural changes:
1. Move code pulling to the Runner class
Ensures flow code and configuration are present before creating execution processes. This resolves the ordering problem by handling pull steps (including code retrieval) before spawning the flow run process.
Implementation considerations:
- Must handle
change_working_directorystep carefully (use as base path rather than process-wide change) - Pull steps should complete before any process creation
2. Update Runner to use uv run automatically
If a pyproject.toml is present in the working directory, the Runner should automatically use uv run for flow execution. The Runner would still function as a crash observer and cancellation handler.
3. Add module entry point to flow engine
Create a new entry point: python -m prefect.flow_engine <flow_entrypoint> to allow the runner to kick off flows via uv run -m prefect.flow_engine <flow_entrypoint>.
Implementation considerations:
- Support both module paths and file paths (e.g.,
/path/to/file.py:flow_name) - Should apply minimal
@flowdecorator if function isn't already decorated - Entry point should be similar to existing
python -m prefect.enginepattern
4. Update flow engine to respect PREFECT__FLOW_RUN_ID env var
Mirror how python -m prefect.engine works, giving users the option to opt out of using a Runner by directly using uv run -m prefect.flow_engine <flow_entrypoint> via the command job variable.
Implementation considerations:
- Should fetch flow run from API if not already provided
- Should only occur if run context is not active (not for child flow runs)
- Provides flexibility for advanced users who want direct control
Benefits
- Zero configuration: "Just works" with no user changes if already using
uv - No new interface surface area: Leverages existing patterns and tools
- Ecosystem alignment: Provides a recommended project structure aligned with a major Python ecosystem player
- Backward compatible: Existing deployments continue to work unchanged
Alternatives Considered
Add a --launcher option for prefect flow-run execute (Rejected)
This would allow users to specify a custom launcher command.
Why rejected: Too extensible but easy to misconfigure. Would introduce new interface surface area and potential for user error.
Create a uv sync pull step (Rejected)
Users could add a pull step that runs uv sync after code is pulled.
Why rejected:
- Requires user action and configuration
- Virtual environment management may not work as expected depending on
uvconfiguration - Doesn't allow Python version management
- Fragile to changes in
uvbehavior
User Impact
Users with existing uv projects will be able to:
- Define dependencies in
pyproject.toml(standard Python practice) - Push code to Git repositories
- Have Prefect workers pull and execute flows using
uvautomatically - Manage Python versions via
pyproject.toml
No changes required for users not using uv - existing deployments continue to work unchanged.