Enhanced support for uv dynamic virtual environments in Prefect agent executions #18223
Replies: 6 comments
-
|
hi @eduardojandre - thanks for the write-up! this is possible today by overriding the
we are unlikely to do this, because the above escape hatch already exists and there is a great deal of variation on what "automation detection" could mean here additionally, you might be interested in ad-hoc infra submission. docs: https://docs.prefect.io/v3/deploy/submit-flows-directly-to-dynamic-infrastructure given the optionality that exists today and the documented plans to expand ad-hoc infra over time, I think we can close this issue. what do you think? |
Beta Was this translation helpful? Give feedback.
-
|
Hi @zzstoatzz, thank you very much for the super quick response! I appreciate the flexibility that Prefect offers with Specifically, I was trying to set up something like this: deployments:
- name: test-labs-uv4
...
pull:
- prefect.deployments.steps.git_clone:
id: clone-step
repository: "https://dev.azure.com/prefect-demo/_git/prefect-demo"
branch: "testeduardo"
access_token: "{{ prefect.blocks.secret.azure-devops-token }}"
- prefect.deployments.steps.run_shell_script:
script: |
uv venv .venv
uv pip install -r requirements.txt
work_pool:
name: my-work-pool
job_variables:
command: "uv run -m prefect.engine"But since the repo isn’t cloned yet when command runs, the environment isn’t available, so this approach doesn’t quite solve the problem I’m aiming to address. I completely understand the concern about generalizing "automatic detection," especially given the variations in environments. I also looked into ad-hoc infrastructure submission as you suggested — while it’s a great feature, it doesn’t quite fit my use case either. My use case is to support lightweight flows with slightly different dependency requirements, all running on the same worker, without having to manage and provision entire container images for each variation. I also understand what I proposed as a solution will not work either because of the order. Thanks again! |
Beta Was this translation helpful? Give feedback.
-
|
hi @eduardojandre - i think you have a good point that we could improve this. it might be a another worker type, built-in step but there is definitely a gap here incomplete initial assessmentyou shouldn't need both. you're correct about the sequencing, but I'm suggesting you could either
in this case it sounds like you'd prefer the latter, so check out this example: » prefect deployment run 'uses-pandas/deployment-3'
Creating flow run for deployment 'uses-pandas/deployment-3'...
Created flow run 'eccentric-caterpillar'.
└── UUID: b1e8875a-a358-4abc-9a4b-d9c1cc21dc6f
└── Parameters: {}
└── Job Variables: {}
└── Scheduled start time: 2025-05-28 16:18:33 CDT (now)
└── URL: http://127.0.0.1:4200/runs/flow-run/b1e8875a-a358-4abc-9a4b-d9c1cc21dc6f
» uv run --isolated prefect worker start --pool 'local' --run-once
Installed 134 packages in 239ms
Discovered type 'process' for work pool 'local'.
Worker 'ProcessWorker bae703d0-8d76-4078-b457-0e09c236f168' started!
16:18:46.965 | INFO | prefect.flow_runs.worker - Worker 'ProcessWorker bae703d0-8d76-4078-b457-0e09c236f168' submitting flow run 'b1e8875a-a358-4abc-9a4b-d9c1cc21dc6f'
16:18:47.015 | INFO | prefect.flow_runs.runner - Opening process...
16:18:47.037 | INFO | prefect.flow_runs.worker - Completed submission of flow run 'b1e8875a-a358-4abc-9a4b-d9c1cc21dc6f'
16:18:47.612 | INFO | Flow run 'eccentric-caterpillar' - > Running git_clone step...
16:18:48.080 | INFO | Flow run 'eccentric-caterpillar' - > Running run_shell_script step...
Resolved 7 packages in 7ms
Installed 3 packages in 62ms
+ emoji==2.14.1
+ numpy==2.2.6
+ pandas==2.2.3
16:18:48.700 | INFO | Flow run 'eccentric-caterpillar' - Beginning flow run 'eccentric-caterpillar' for flow 'uses-pandas'
16:18:48.700 | INFO | Flow run 'eccentric-caterpillar' - View at http://127.0.0.1:4200/runs/flow-run/b1e8875a-a358-4abc-9a4b-d9c1cc21dc6f
16:18:55.115 | INFO | Flow run 'eccentric-caterpillar' - a b
0 1 4
1 2 5
2 3 6
16:18:55.142 | INFO | Flow run 'eccentric-caterpillar' - Finished in state Completed()
16:18:55.266 | INFO | prefect.flow_runs.runner - Process for flow run 'eccentric-caterpillar' exited cleanly.
Worker 'ProcessWorker bae703d0-8d76-4078-b457-0e09c236f168' stopped!
» uv pip list | rg pandasyou should have full flexibility via for example, you might want to define |
Beta Was this translation helpful? Give feedback.
-
|
Checking in on this thread if anyone has found anything hacky but functional? I have tried the pair of uv sync --directory {repo} and gotten packages to download but |
Beta Was this translation helpful? Give feedback.
-
|
I'm also interested in a workaround. My use case is to upgrade my package from the cloned repo, in a next step, running in a process worker. |
Beta Was this translation helpful? Give feedback.
-
|
@eduardojandre Is completely right, the current solutions using @zzstoatzz The point about the race condition above is why your "incomplete initial assessment" above is not a good enough solution, even temporarily. If two flows start simultaneously and run @NTC4818 @leo-selfee The only hacky solution I've found so far is to use an approach based on the More precisely, I essentially specify the repo (which is uv-based, meaning has a pull:
- prefect.deployments.steps.git_clone:
repository: git@github.mycompany.com:myproject/myproject.git
branch: "{{ $MYPROJECT_BRANCH }}"
definitions:
deployments:
local_pool_deployment: &local_pool_deployment
work_pool:
name: local
job_variables:
command: uv run --with git+ssh://git@github.mycompany.com/myproject/myproject.git@{{ $MYPROJECT_BRANCH }} python -m prefect.engine
deployments:
- <<: *local_pool_deployment
name: some-deployment
entrypoint: src/myproject/deployments/some_deployment.py:main
schedules:
- cron: 0 19 * * Mon-Fri
timezone: US/EasternThis pretty much works as one would like and there's no race conditions between flows running simultaneously as they will each create a temporary implicit virtual env on the fly thanks to the
Given all the above I agree with @eduardojandre very much that Prefect devs need to find a solution here. There has got to be a way to dynamically create and use Python environments independently for each flow run, especially nowadays that environment specifications are mostly declarative and can be committed to and pinned in repositories themselves. Not having this functionality makes the whole git pull step mechanism somewhat incomplete and pointless at this stage. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Describe the current behavior
Currently, Prefect agents execute flows using the environment in which the agent process is running. While this works well in homogeneous environments, it complicates scenarios where different flows require distinct Python environments or dependency sets.
The current alternatives — using multiple agent configurations or dynamically instantiated containers with specialized images — introduce additional operational complexity, infrastructure overhead, and slower startup times.
Describe the proposed behavior
Proposed Behavior
Introduce a mechanism within the Prefect agent or flow runner that allows:
Potential Implementation Ideas
Modify
src/prefect/workers/process.py(ProcessWorker) to support automatic detection of a.venvoruvenvironment in the cloned repository.If such an environment exists, the worker can invoke the flow run using the Python binary within that virtual environment, instead of the agent's default
sys.executable.Consider extending similar logic to other workers to support it, ensuring consistent behavior across different deployment types, including containerized and Kubernetes-based workers.
Provide a configuration option (e.g., environment variable or deployment setting) to enable or disable this auto-detection and invocation of virtual environments, allowing for flexible adoption.
Example Use
An organization operates a Prefect agent on a shared server where multiple teams deploy flows with different and potentially conflicting dependencies.
With this feature, each team can commit their flow code, and use a Utility step on the pull action to create a dedicated
.venvoruvenvironment within their repository. When the flow is deployed and executed by the agent:pythonbinary inside the detected environment.For example:
pandas==1.5.pandas==2.2.Both flows can run independently on the same agent using their respective virtual environments, improving deployment flexibility and minimizing dependency conflicts.
Additional context
Benefits
Simplified and Faster Iteration
Switching Python environments via virtual environments (
venv,uv, etc.) can be faster and simpler than building, pushing, and managing container images. Developers can adjust dependencies without modifying deployment infrastructure.Additionally, execution startup time can be significantly reduced on some scenarios — invoking a subprocess using the environment's Python binary is can be faster than instantiating a new container. This makes the approach particularly well-suited for short-lived flows or frequent deployments.
Greater Flexibility in Deployment
Enables the use of multiple Python environments within a single worker, allowing diverse flows with different dependencies to coexist without requiring container orchestration.
Improved Compatibility
Supports scenarios where running inside a container is restricted,
Beta Was this translation helpful? Give feedback.
All reactions