Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 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
34 changes: 34 additions & 0 deletions .yarn/versions/85334687.yml
Copy link
Member

Choose a reason for hiding this comment

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

In it's current state this PR is a major change.

Copy link
Member

@arcanis arcanis Aug 6, 2023

Choose a reason for hiding this comment

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

Indeed - although once moved as optional parameters in the option bags it'll be fine as a minor (only the modified packages + cli can be marked as minor, the rest can be declined).

Copy link
Author

@anuragkalia anuragkalia Aug 7, 2023

Choose a reason for hiding this comment

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

Changed the version file to bump only the changed plugins as well as @yarnpkg/core and @yarnpkg/cli to minor.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
releases:
"@yarnpkg/cli": minor
"@yarnpkg/core": minor
"@yarnpkg/plugin-file": minor
"@yarnpkg/plugin-git": minor
"@yarnpkg/plugin-github": minor
"@yarnpkg/plugin-http": minor
"@yarnpkg/plugin-npm": minor

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-essentials"
- "@yarnpkg/plugin-exec"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-link"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/doctor"
- "@yarnpkg/extensions"
- "@yarnpkg/nm"
- "@yarnpkg/pnpify"
- "@yarnpkg/sdks"
7 changes: 7 additions & 0 deletions packages/docusaurus/static/configuration/yarnrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@
"type": "number",
"default": 50
},
"workerPoolConcurrency": {
"_package": "@yarnpkg/core",
"title": "Amount of workers that are allowed to run at the same time.",
"description": "We default to the platform parallelism, but for some CI, `os.cpus` may not report accurate values and may overwhelm their containers",
"type": "number",
"default": "os.availableParallelism()"
},
"networkSettings": {
"_package": "@yarnpkg/core",
"title": "Additional network settings, per hostname",
Expand Down
7 changes: 7 additions & 0 deletions packages/gatsby/static/configuration/yarnrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@
"default": 50,
"examples": [8]
},
"workerPoolConcurrency": {
"_package": "@yarnpkg/core",
"description": "Defines how many workers that are allowed to run at the same time. Yarn defaults to platform parallelism but for some CI, `os.cpus` may not report accurate values and may overwhelm their containers.",
"type": "number",
"default": "os.availableParallelism()",
"examples": [8]
},
"networkSettings": {
"_package": "@yarnpkg/core",
"description": "Additional network settings, per hostname",
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-file/sources/TarballFileFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class TarballFileFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
}
}
1 change: 1 addition & 0 deletions packages/plugin-git/sources/GitFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export class GitFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-github/sources/GithubFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class GithubFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-http/sources/TarballHttpFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class TarballHttpFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
}
}
1 change: 1 addition & 0 deletions packages/plugin-npm/sources/NpmHttpFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class NpmHttpFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
}
}
1 change: 1 addition & 0 deletions packages/plugin-npm/sources/NpmSemverFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class NpmSemverFetcher implements Fetcher {
compressionLevel: opts.project.configuration.get(`compressionLevel`),
prefixPath: structUtils.getIdentVendorPath(locator),
stripComponents: 1,
poolSize: opts.project.configuration.getLimit(`workerPoolConcurrency`),
});
}

Expand Down
6 changes: 6 additions & 0 deletions packages/yarnpkg-core/sources/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ export const coreDefinitions: {[coreSettingName: string]: SettingsDefinition} =
type: SettingsType.NUMBER,
default: 50,
},
workerPoolConcurrency: {
description: `Maximal number of workers in the worker pool`,
type: SettingsType.NUMBER,
default: nodeUtils.availableParallelism(),
},
networkSettings: {
description: `Network settings per hostname (glob patterns are supported)`,
type: SettingsType.MAP,
Expand Down Expand Up @@ -636,6 +641,7 @@ export interface ConfigurationValueMap {
httpsKeyFilePath: PortablePath | null;
httpsCertFilePath: PortablePath | null;
enableStrictSsl: boolean;
workerPoolConcurrency: number;

logFilters: Array<miscUtils.ToMapValue<{code?: string, text?: string, pattern?: string, level?: formatUtils.LogLevel | null}>>;

Expand Down
18 changes: 13 additions & 5 deletions packages/yarnpkg-core/sources/WorkerPool.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import PLimit from 'p-limit';
import {Worker} from 'worker_threads';
import PLimit, {Limit} from 'p-limit';
import {Worker} from 'worker_threads';

import * as nodeUtils from './nodeUtils';
import * as nodeUtils from './nodeUtils';

const kTaskInfo = Symbol(`kTaskInfo`);

type PoolWorker<TOut> = Worker & {
[kTaskInfo]: null | { resolve: (value: TOut) => void, reject: (reason?: any) => void };
};

type WorkerPoolOptions = {
poolSize?: Limit;
};

export class WorkerPool<TIn, TOut> {
private workers: Array<PoolWorker<TOut>> = [];
private limit = PLimit(nodeUtils.availableParallelism());

private cleanupInterval: ReturnType<typeof setInterval>;

constructor(private source: string) {
private limit: Limit;

constructor(private source: string, opts: WorkerPoolOptions = {}) {
this.limit = opts.poolSize ?? PLimit(nodeUtils.availableParallelism());

this.cleanupInterval = setInterval(() => {
if (this.limit.pendingCount === 0 && this.limit.activeCount === 0) {
// Start terminating one worker at a time when there are no tasks left.
Expand Down
17 changes: 14 additions & 3 deletions packages/yarnpkg-core/sources/tgzUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {FakeFS, PortablePath, NodeFS, ppath, xfs, npath, constants} from '@yarnpkg/fslib';
import {ZipCompression, ZipFS} from '@yarnpkg/libzip';
import {Limit} from 'p-limit';
import {PassThrough, Readable} from 'stream';
import tar from 'tar';

Expand Down Expand Up @@ -37,15 +38,25 @@ export interface ExtractBufferOptions {
stripComponents?: number;
}

export interface ConvertToZipOptions extends ExtractBufferOptions {
poolSize?: Limit;
}

let workerPool: WorkerPool<ConvertToZipPayload, PortablePath> | null;

export async function convertToZip(tgz: Buffer, opts: ExtractBufferOptions) {
export async function convertToZip(tgz: Buffer, opts: ConvertToZipOptions) {
const tmpFolder = await xfs.mktempPromise();
const tmpFile = ppath.join(tmpFolder, `archive.zip`);

workerPool ||= new WorkerPool(getZipWorkerSource());
workerPool ||= new WorkerPool(getZipWorkerSource(), {poolSize: opts.poolSize});

const bufferOpts: ExtractBufferOptions = {
compressionLevel: opts.compressionLevel,
prefixPath: opts.prefixPath,
stripComponents: opts.stripComponents,
};

await workerPool.run({tmpFile, tgz, opts});
await workerPool.run({tmpFile, tgz, opts: bufferOpts});

return new ZipFS(tmpFile, {level: opts.compressionLevel});
}
Expand Down
5 changes: 3 additions & 2 deletions packages/yarnpkg-core/tests/tgzUtils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {npath, xfs} from '@yarnpkg/fslib';
import pLimit from 'p-limit';

import * as tgzUtils from '../sources/tgzUtils';

Expand All @@ -10,7 +11,7 @@ describe(`tgzUtils`, () => {
npath.join(__dirname, `fixtures/carbon-icons-svelte-10.21.0.tgz`),
),
);
await expect(tgzUtils.convertToZip(data, {compressionLevel: 0})).resolves.toBeTruthy();
await expect(tgzUtils.convertToZip(data, {compressionLevel: 0, poolSize: pLimit(2)})).resolves.toBeTruthy();
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason to use an explicit pool size here rather than the default?

});

it(`should be able to convert a tgz without compression`, async () => {
Expand All @@ -19,7 +20,7 @@ describe(`tgzUtils`, () => {
npath.join(__dirname, `fixtures/parse5-0.0.28.tgz`),
),
);
await expect(tgzUtils.convertToZip(data, {compressionLevel: 0})).resolves.toBeTruthy();
await expect(tgzUtils.convertToZip(data, {compressionLevel: 0, poolSize: pLimit(2)})).resolves.toBeTruthy();
});
});
});