Skip to content

Support common Unix resource limits in uv run - #553

Draft
zaniebot wants to merge 7 commits into
mainfrom
zb/uv-run-resource-limits
Draft

zaniebot wants to merge 7 commits into
mainfrom
zb/uv-run-resource-limits

Conversation

@zaniebot

@zaniebot zaniebot commented Aug 5, 2026 •

Copy link
Copy Markdown
Collaborator

uv run currently only exposes RLIMIT_NOFILE (astral-sh#20926), leaving common Unix resource controls unavailable for commands it launches.

Add UV_RUN_RLIMIT_CPU, UV_RUN_RLIMIT_AS, UV_RUN_RLIMIT_FSIZE, UV_RUN_RLIMIT_NPROC, and UV_RUN_RLIMIT_CORE alongside UV_RUN_RLIMIT_NOFILE. Apply configured soft limits immediately before spawning the command, preserve their hard limits, and accept 64-bit resource values.

@zaniebot zaniebot changed the title Support all Unix resource limits in uv run Support common Unix resource limits in uv run Aug 5, 2026
@astral-automations-bot astral-automations-bot Bot added the area:configuration Settings and such label Aug 5, 2026
@zaniebot zaniebot added priority:3 Normal: useful features, documentation, usability, or routine efficiency improvements. size:3 Substantial: interacting behaviors, difficult compatibility questions, or a careful migration. risk:3 Credible risk of meaningful incorrect behavior or regression; bounded or recoverable. labels Sep 9, 2026
@astral-automations-bot
astral-automations-bot Bot force-pushed the zb/uv-run-resource-limits branch from 16a587a to 75612b1 Compare September 11, 2026 19:19
@codspeed

codspeed Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 8 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 54 untouched benchmarks
⏩ 35 skipped benchmarks1


Comparing zb/uv-run-resource-limits (16473e0) with main (f7e9e6a)2

Open in CodSpeed

Footnotes

  1. 35 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (699b4f9) during the generation of this report, so f7e9e6a was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@astral-automations-bot
astral-automations-bot Bot force-pushed the zb/uv-run-resource-limits branch from 75612b1 to f013569 Compare September 17, 2026 22:06
@zaniebot zaniebot added the build:skip-release Disable building release binaries for a pull request label Oct 7, 2026
@astral-automations-bot
astral-automations-bot Bot force-pushed the zb/uv-run-resource-limits branch from f013569 to 04ff844 Compare October 7, 2026 20:44
Comment thread crates/uv-project-commands/src/run.rs Outdated
Comment on lines +1265 to +1266
for resource_limit in run_resource_limits {
resource_limit.apply().with_context(|| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Apply the new resource limits in the child process

apply() changes uv's own limits before .spawn(). If uv's address space already exceeds the requested RLIMIT_AS, spawning a small command can fail with ENOMEM; similarly, RLIMIT_CPU counts CPU time uv already spent preparing the environment. Isolated Linux probes confirmed both failure modes. The test's 1 PiB address-space limit avoids this problem. Validate limits in the parent, apply them in the child's pre-exec path, and cover a realistic memory limit.

Comment on lines +308 to +309
fn u64_to_rlim_t(value: u64) -> Option<rlim_t> {
rlim_t::try_from(value).ok()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Handle the platform-dependent conversion lint

On Linux and macOS, rlim_t is u64, so this triggers clippy::useless_conversion. An isolated check of the extracted helper with that alias reproduced the warning; the Linux CI job denies warnings. Mirror the #[expect(clippy::useless_conversion)] on rlim_t_to_u64 immediately above, retaining the checked conversion needed on signed platforms.

Comment thread crates/uv-static/src/env_vars.rs Outdated
Comment on lines +1409 to +1410
#[attr_added_in("0.12.2")]
pub const UV_RUN_RLIMIT_AS: &'static str = "UV_RUN_RLIMIT_AS";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Record the actual introduction version for the new variables

All five new variables claim support since 0.12.2, and the reference generator renders this metadata verbatim. However, the available uv 0.12.13 still ignores UV_RUN_RLIMIT_CPU=60, leaving the child's limit unlimited. This advertises support in versions that silently leave limits unset. Update all five annotations to the release introducing this feature.

@zaniebot
zaniebot deployed to automations October 9, 2026 00:13 — with GitHub Actions Active
@zaniebot
zaniebot deployed to automations October 9, 2026 00:19 — with GitHub Actions Active
Comment thread crates/uv/tests/it/resource_limits.rs Outdated
.arg(python)
.arg("-c")
.arg("import resource; print(resource.getrlimit(resource.RLIMIT_NPROC)[0])")
.env(EnvVars::UV_RUN_RLIMIT_NPROC, "4096");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Use a process limit below typical macOS hard limits

This success test assumes the inherited hard RLIMIT_NPROC is at least 4096. macOS installations can have a hard limit of 2666, in which case ResourceLimit::prepare correctly returns ExceedsHardLimit before Python runs. Use a smaller soft limit, such as 128, and update the snapshot so this test exercises the override without requiring an unusually high host limit.

Comment on lines +54 to +56
#[test]
fn run_resource_limit_overrides() {
let context = uv_test::test_context!("3.12");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Gate the new Python-dependent tests

Unlike run_memory_limit_applies_only_to_child, the other four new tests lack a test-python gate. The containing module is gated only on Unix, and test_context!("3.12") requires that interpreter during setup. These cases therefore fail when Python-dependent tests are disabled and Python 3.12 is unavailable. Add the feature gate to the new cases, or gate the resource-limit module.

@zaniebot
zaniebot deployed to automations October 9, 2026 16:21 — with GitHub Actions Active
@zaniebot
zaniebot deployed to automations October 9, 2026 16:27 — with GitHub Actions Active
Comment on lines +1282 to +1284
process.pre_exec(move || {
for limit in &resource_limits {
limit.apply()?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Retain configured limits in spawn-error diagnostics

prepare() checks representability and the inherited hard limit, but setrlimit can still fail—for example, macOS rejects RLIMIT_NOFILE above kern.maxfilesperproc even with an unlimited hard limit. Returning only errno here routes that failure through the generic Failed to spawn context, losing the environment variable and requested value that the previous implementation reported. Retain the configured names and values in the parent and include them in spawn-error context, while keeping the callback allocation-free.

Comment thread crates/uv/tests/it/resource_limits.rs Outdated
Comment on lines +155 to +158
#[test]
fn run_resource_limit_override_invalid() {
let context = uv_test::test_context!("3.12");
let python = &context.python_versions[0].1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Remove duplicated generic validation scenarios

This test repeats run_open_file_limit_override_invalid through the same parse_integer_environment_variable::<u64> path. Likewise, the new CPU hard-limit failure test repeats the shared ResourceLimit::prepare branch already covered by run_open_file_limit_override_exceeds_hard_limit. The combined success test already verifies CPU-variable wiring. Remove these two CPU error scenarios and retain the existing NOFILE cases; this avoids maintaining duplicate integration setup and diagnostic snapshots without losing coverage of a distinct validation path.

@zaniebot
zaniebot deployed to automations October 9, 2026 17:03 — with GitHub Actions Active
@zaniebot
zaniebot deployed to automations October 9, 2026 17:08 — with GitHub Actions Active
Comment on lines +1416 to +1418
/// Sets the soft CPU-time limit, in seconds, for commands executed by `uv run`.
#[attr_added_in("next release")]
pub const UV_RUN_RLIMIT_CPU: &'static str = "UV_RUN_RLIMIT_CPU";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Document the Unix restriction for all new limits

The descriptions for UV_RUN_RLIMIT_CPU, UV_RUN_RLIMIT_CORE, and UV_RUN_RLIMIT_FSIZE omit the Unix-only restriction stated for the other limits. These descriptions populate the environment-variable reference, but parsing and application are gated by #[cfg(unix)], so the variables silently do nothing on Windows. Add the same platform note to these three entries.

Comment on lines -109 to -110
if hard != RLIM_INFINITY && target_rlim > hard {
return Err(OpenFileLimitError::ExceedsHardLimit { target, hard });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Remove the obsolete open-file error variant

Deleting this function removes the only construction of OpenFileLimitError::ExceedsHardLimit. The remaining adjust_open_file_limit path clamps its target, while configured-limit validation now uses ResourceLimitError::ExceedsHardLimit. Remove the obsolete variant alongside this function so the exported error type reflects the failures its operations can actually produce.

@zaniebot
zaniebot deployed to automations October 9, 2026 17:46 — with GitHub Actions Active
@zaniebot
zaniebot deployed to automations October 9, 2026 17:51 — with GitHub Actions Active
Comment thread crates/uv-unix/src/resource_limits.rs Outdated
Comment on lines +86 to +90
pub fn new(environment_variable: &'static str, resource: RunResource, value: u64) -> Self {
Self {
environment_variable,
resource,
value,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Keep resource identity and its environment name together

This constructor accepts the environment-variable name and kernel resource independently, while prepare() derives the diagnostic resource name from that string. The sole caller currently forwards matching pairs from SUPPORTED_RESOURCE_LIMITS, but the public API makes callers responsible for keeping the reported resource aligned with the resource actually applied, including choosing the nix/rustix backend. Represent supported resources with a closed resource-kind enum or an opaque descriptor that owns both mappings, and construct limits from that resource plus the value. This keeps the pairing invariant inside uv-unix without changing the prepared-limit boundary.

@zaniebot
zaniebot deployed to automations October 9, 2026 18:09 — with GitHub Actions Active

This branch was successfully deployed

1 active deployment
automations — 16473e00 Deployed Oct 9, 2026 by zaniebot via review-code-quality / code quality review #9092
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:configuration Settings and such build:skip-release Disable building release binaries for a pull request priority:3 Normal: useful features, documentation, usability, or routine efficiency improvements. risk:3 Credible risk of meaningful incorrect behavior or regression; bounded or recoverable. size:3 Substantial: interacting behaviors, difficult compatibility questions, or a careful migration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants