Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions completions/bun-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -748,7 +748,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -1079,7 +1079,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -1351,7 +1351,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -1769,7 +1769,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -2149,7 +2149,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -2432,7 +2432,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -2691,7 +2691,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -2943,7 +2943,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -3248,7 +3248,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down Expand Up @@ -3677,7 +3677,7 @@
},
{
"name": "network-concurrency",
"description": "Maximum number of concurrent network requests (default 48)",
"description": "Maximum number of concurrent network requests (default 64)",
"hasValue": true,
"valueType": "val",
"required": false,
Expand Down
2 changes: 1 addition & 1 deletion docs/snippets/cli/add.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ bun add <package> <@version>
variables
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests
</ParamField>

Expand Down
2 changes: 1 addition & 1 deletion docs/snippets/cli/install.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ bun install <name>@<version>
Maximum number of concurrent jobs for lifecycle scripts (default: 2x CPU cores)
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests
</ParamField>

Expand Down
2 changes: 1 addition & 1 deletion docs/snippets/cli/link.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ bun link <packages>
variables
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests
</ParamField>

Expand Down
4 changes: 2 additions & 2 deletions docs/snippets/cli/outdated.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ bun outdated <filter>
Use a specific registry by default, overriding <code>.npmrc</code>, <code>bunfig.toml</code> and environment variables
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
Maximum number of concurrent network requests (default 48)
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests (default 64)
</ParamField>

### Caching
Expand Down
4 changes: 2 additions & 2 deletions docs/snippets/cli/patch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ bun patch <package>@<version>
variables
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
Maximum number of concurrent network requests (default 48)
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests (default 64)
</ParamField>

### Performance &amp; Resource
Expand Down
2 changes: 1 addition & 1 deletion docs/snippets/cli/publish.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ bun publish --cafile ./ca-cert.pem
Platform optimizations: `clonefile` (default), `hardlink`, `symlink`, or `copyfile`
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
<ParamField path="--network-concurrency" type="number" default="64">
Maximum concurrent network requests
</ParamField>

Expand Down
4 changes: 2 additions & 2 deletions docs/snippets/cli/remove.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,6 @@ bun remove <package>
<code>hardlink</code>, <code>symlink</code>, <code>copyfile</code>
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
Maximum number of concurrent network requests (default 48)
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests (default 64)
</ParamField>
4 changes: 2 additions & 2 deletions docs/snippets/cli/update.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ bun up
Use a specific registry by default, overriding <code>.npmrc</code>, <code>bunfig.toml</code> and environment variables
</ParamField>

<ParamField path="--network-concurrency" type="number" default="48">
Maximum number of concurrent network requests (default 48)
<ParamField path="--network-concurrency" type="number" default="64">
Maximum number of concurrent network requests (default 64)
</ParamField>

### Caching
Expand Down
13 changes: 10 additions & 3 deletions src/install/PackageManager/CommandLineArguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ const BACKEND_PARAM: ParamType = clap::param!(
"--backend <STR> Platform-specific optimizations for installing dependencies. Possible values: \"hardlink\" (default), \"symlink\", \"copyfile\""
);

const NETWORK_CONCURRENCY_PARAM: ParamType = clap::param!(
"--network-concurrency <NUM> Maximum number of concurrent network requests (default 64)"
);
const _: () = assert!(
super::DEFAULT_MAX_SIMULTANEOUS_REQUESTS_FOR_BUN_INSTALL == 64
&& super::DEFAULT_MAX_SIMULTANEOUS_REQUESTS_FOR_BUN_INSTALL_FOR_PROXIES == 64,
"update the default in the --network-concurrency help text (and docs/snippets/cli/*.mdx)"
);

const SHARED_HEAD_PARAMS: &[ParamType] = &[
clap::param!("-c, --config <STR>? Specify path to config file (bunfig.toml)"),
clap::param!("-y, --yarn Write a yarn.lock file (yarn v1)"),
Expand Down Expand Up @@ -103,9 +112,7 @@ const SHARED_TAIL_PARAMS: &[ParamType] = &[
clap::param!(
"--concurrent-scripts <NUM> Maximum number of concurrent jobs for lifecycle scripts (default: 2x CPU cores)"
),
clap::param!(
"--network-concurrency <NUM> Maximum number of concurrent network requests (default 48)"
),
NETWORK_CONCURRENCY_PARAM,
clap::param!("--save-text-lockfile Save a text-based lockfile"),
clap::param!(
"--omit <dev|optional|peer>... Exclude 'dev', 'optional', or 'peer' dependencies from install"
Expand Down
80 changes: 80 additions & 0 deletions test/cli/install/bun-install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,66 @@ async function withContext(
// Default context options for most tests
const defaultOpts = { linker: "hoisted" as const };

// BUN_CONFIG_MAX_HTTP_REQUESTS is documented as another way to set the request
// limit, so it must not leak in from the outer environment while measuring it.
const networkConcurrencyEnv = { ...env, BUN_CONFIG_MAX_HTTP_REQUESTS: undefined };

// Runs `bun install` with one dependency more than `limit`, against a registry
// that holds every manifest request open, and asserts that bun has exactly
// `limit` requests in flight: the extra dependency has to wait for a slot.
async function expectInstallInFlightLimit(ctx: TestContext, limit: number) {
const dependencies: Record<string, string> = {};
for (let i = 0; i < limit + 1; i++) dependencies[`dep-${i}`] = "^1";
await writeFile(
join(ctx.package_dir, "package.json"),
JSON.stringify({ name: "foo", version: "0.0.1", dependencies }),
);

let inFlight = 0;
let maxInFlight = 0;
const limitReached = Promise.withResolvers<void>();
const limitExceeded = Promise.withResolvers<void>();
const release = Promise.withResolvers<void>();
setContextHandler(ctx, async () => {
inFlight++;
maxInFlight = Math.max(maxInFlight, inFlight);
if (inFlight >= limit) limitReached.resolve();
if (inFlight > limit) limitExceeded.resolve();
await release.promise;
inFlight--;
return new Response("404", { status: 404 });
});

await using proc = spawn({
cmd: [bunExe(), "install"],
cwd: ctx.package_dir,
stdout: "pipe",
stderr: "pipe",
stdin: "ignore",
env: networkConcurrencyEnv,
});
try {
// A real limit below `limit` parks bun (and this wait) with fewer requests
// in flight and no further signal, so the wait is bounded (generously: this
// is a debug build under CI load) and the assertions below report what was
// reached. proc.exited covers bun giving up early.
await Promise.race([limitReached.promise, proc.exited, Bun.sleep(30_000)]);
// bun sends everything its limit allows in one burst, so a request beyond
// the limit arrives right behind the others. That it never arrives can only
// be observed by giving it a moment to show up.
await Promise.race([limitExceeded.promise, Bun.sleep(500)]);
} finally {
release.resolve();
}
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);

expect(maxInFlight).toBe(limit);
expect(ctx.requested).toBe(limit + 1);
expect(stderr).toContain("failed to resolve");
expect(stdout).toContain("bun install v1.");
expect(exitCode).toBe(1);
}

const gitEnv = {
...bunEnv,
GIT_AUTHOR_NAME: "bun-test",
Expand Down Expand Up @@ -121,6 +181,26 @@ function serveDirectory(root: string) {
}

describe.concurrent("bun-install", () => {
it("bun install --help states the --network-concurrency default that bun install actually uses", async () => {
await using help = spawn({
cmd: [bunExe(), "install", "--help"],
stdout: "pipe",
stderr: "pipe",
env,
});
const [helpStdout, helpStderr, helpExitCode] = await Promise.all([
help.stdout.text(),
help.stderr.text(),
help.exited,
]);
const helpLine = (helpStdout + helpStderr).split(/\r?\n/).find(line => line.includes("--network-concurrency"));
const documentedDefault = /Maximum number of concurrent network requests \(default (\d+)\)$/.exec(helpLine ?? "");
expect(documentedDefault).not.toBeNull();
expect(helpExitCode).toBe(0);

await withContext(defaultOpts, ctx => expectInstallInFlightLimit(ctx, Number(documentedDefault![1])));
});

for (let input of ["abcdef", "65537", "-1"]) {
it(`bun install --network-concurrency=${input} fails`, async () => {
await withContext(defaultOpts, async ctx => {
Comment thread
claude[bot] marked this conversation as resolved.
Expand Down
Loading