Skip to content

Commit

Permalink
ues pool
Browse files Browse the repository at this point in the history
  • Loading branch information
Feverqwe committed Oct 29, 2023
1 parent 1c60dd8 commit afedccc
Show file tree
Hide file tree
Showing 13 changed files with 326 additions and 422 deletions.
3 changes: 1 addition & 2 deletions scripts/build.cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ const commonConfig = {

const builds = [
[['src/index.ts'], 'build/index.js'],
[['src/workers/linter/index.ts'], 'build/linter.js'],
[['src/workers/transform/index.ts'], 'build/transform.js'],
[['src/workers/pool/index.ts'], 'build/pool.js'],
];

Promise.all(builds.map(([entries, outfile]) => {
Expand Down
42 changes: 25 additions & 17 deletions src/cmd/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ import {join, resolve} from 'path';
import {ArgvService, Includers} from '../../services';
import OpenapiIncluder from '@diplodoc/openapi-extension/includer';
import {
initLinterWorkers,
initProcessWorkers,
processAssets,
processExcludedFiles,
processLinter,
processLogs,
processPages,
processServiceFiles,
saveSinglePages,
} from '../../steps';
import {prepareMapFile} from '../../steps/processMapFile';
import shell from 'shelljs';
Expand All @@ -29,6 +28,12 @@ import {copyFiles, logger} from '../../utils';
import {upload as publishFilesToS3} from '../publish/upload';
import glob from 'glob';
import {createVCSConnector} from '../../vcs-connector';
import {
finishProcessPool,
getPoolEnv,
initProcessPool,
terminateProcessPool,
} from '../../steps/processPool';

export const build = {
command: ['build', '$0'],
Expand Down Expand Up @@ -199,6 +204,7 @@ async function handler(args: Arguments<any>) {
addMapFile,
allowCustomResources,
resources,
singlePage,
} = ArgvService.getConfig();

preparingTemporaryFolders(userOutputFolder);
Expand All @@ -215,28 +221,29 @@ async function handler(args: Arguments<any>) {
const pathToRedirects = join(args.input, REDIRECTS_FILENAME);
const pathToLintConfig = join(args.input, LINT_CONFIG_FILENAME);

const promises: Promise<unknown>[] = [];

const vcsConnector = createVCSConnector();

if (!lintDisabled) {
/* Initialize workers in advance to avoid a timeout failure due to not receiving a message from them */
await initLinterWorkers();
promises.push(processLinter());
}

if (vcsConnector) {
promises.push(vcsConnector.init());
await vcsConnector.init();
}

await Promise.all(promises);
await initProcessPool({vcsConnector});

if (!buildDisabled) {
await initProcessWorkers();
await processPages(vcsConnector);
try {
await Promise.all([
!lintDisabled && processLinter(),
!buildDisabled && processPages(vcsConnector),
]);
await finishProcessPool();
} finally {
await terminateProcessPool();
}

if (!buildDisabled) {
if (singlePage) {
const {singlePageResults} = getPoolEnv();
await saveSinglePages(outputBundlePath, singlePageResults);
}

// process additional files
switch (outputFormat) {
case 'html':
Expand Down Expand Up @@ -314,7 +321,6 @@ function preparingTemporaryFolders(userOutputFolder: string) {
// Create temporary input/output folders
shell.rm('-rf', args.input, args.output);
shell.mkdir(args.input, args.output);
shell.chmod('-R', 'u+w', args.input);

copyFiles(
args.rootInput,
Expand All @@ -326,4 +332,6 @@ function preparingTemporaryFolders(userOutputFolder: string) {
ignore: ['node_modules/**', '*/node_modules/**'],
}),
);

shell.chmod('-R', 'u+w', args.input);
}
5 changes: 3 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ export const REGEXP_INCLUDE_FILE_PATH = /(?<=[(]).+(?=[)])/g;
// Regexp result: authorLogin
export const REGEXP_AUTHOR = /(?<=author:\s).+(?=\r?\n)/g;

export const MIN_CHUNK_SIZE = Number(process.env.MIN_CHUNK_SIZE) || 100;
export const WORKERS_COUNT = Number(process.env.WORKERS_COUNT) || os.cpus().length - 1;
export const MIN_CHUNK_SIZE = Number(process.env.MIN_CHUNK_SIZE) || 10;
export const THREAD_PART_COUNT = Number(process.env.THREAD_PART_COUNT) || 8;
export const WORKERS_COUNT = Number(process.env.WORKERS_COUNT) || os.cpus().length - 1 || 1;

export const metadataBorder = '---';
11 changes: 4 additions & 7 deletions src/resolvers/processPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as fs from 'fs';
import {dump, load} from 'js-yaml';
import {resolveMd2Md} from './md2md';
import {resolveMd2HTML} from './md2html';
import shell from 'shelljs';

let singlePageResults: Record<string, SinglePageResult[]>;
let singlePagePaths: Record<string, Set<string>>;
Expand Down Expand Up @@ -177,7 +178,7 @@ async function preparingPagesByOutputFormat(
(outputFormat === 'md' && isYamlFileExtension) ||
(outputFormat === 'html' && !isYamlFileExtension && fileExtension !== '.md')
) {
await copyFileWithoutChanges(resolvedPathToFile, outputDir, filename);
copyFileWithoutChanges(resolvedPathToFile, outputDir, filename);
return;
}

Expand Down Expand Up @@ -215,15 +216,11 @@ async function processingYamlFile(path: PathData, metaDataOptions: MetaDataOptio
await fs.promises.writeFile(resolve(outputFolderPath, pathToFile), dump(parsedContent));
}

async function copyFileWithoutChanges(
resolvedPathToFile: string,
outputDir: string,
filename: string,
) {
function copyFileWithoutChanges(resolvedPathToFile: string, outputDir: string, filename: string) {
const from = resolvedPathToFile;
const to = resolve(outputDir, filename);

await fs.promises.copyFile(from, to);
shell.cp(from, to);
}

async function processingFileToMd(path: PathData, metaDataOptions: MetaDataOptions): Promise<void> {
Expand Down
102 changes: 22 additions & 80 deletions src/steps/processLinter.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,41 @@
import log from '@diplodoc/transform/lib/log';
import {spawn, Worker, Thread} from 'threads';
import {PluginService, TocService} from '../services';
import {getChunkSize} from '../utils/workers';
import {runPool} from './processPool';
import {chunk} from 'lodash';
import {lintPage} from '../resolvers';
import {extname} from 'path';

import {ArgvService, TocService, PresetService, PluginService} from '../services';
import {ProcessLinterWorker} from '../workers/linter';
import {logger} from '../utils';
import {LINTING_FINISHED, WORKERS_COUNT, MIN_CHUNK_SIZE} from '../constants';
import {lintPage} from '../resolvers';
import {splitOnChunks} from '../utils/worker';
import {getChunkSize} from '../utils/workers';

let processLinterWorkers: (ProcessLinterWorker & Thread)[];
let navigationPathsChunks: string[][];
import {LINTING_FINISHED} from '../constants';

export async function processLinter(): Promise<void> {
const argvConfig = ArgvService.getConfig();

const navigationPaths = TocService.getNavigationPaths();

if (!processLinterWorkers) {
lintPagesFallback(navigationPaths);

if (process.env.DISABLE_PARALLEL_BUILD) {
await lintPagesFallback(navigationPaths);
return;
}

const presetStorageDump = PresetService.dump();

/* Subscribe on the linted page event */
processLinterWorkers.forEach((worker) => {
worker.getProcessedPages().subscribe((pathToFile) => {
logger.info(pathToFile as string, LINTING_FINISHED);
});
});

/* Run processing the linter */
await Promise.all(
processLinterWorkers.map((worker, i) => {
const navigationPathsChunk = navigationPathsChunks[i];

return worker.run({
argvConfig,
navigationPaths: navigationPathsChunk,
presetStorageDump,
});
}),
);

/* Unsubscribe from workers */
await Promise.all(
processLinterWorkers.map((worker) => {
return worker.finish().then((logs) => {
log.add(logs);
});
}),
);
const navigationPathsChunks = chunk(navigationPaths, getChunkSize(navigationPaths));

/* Terminate workers */
await Promise.all(
processLinterWorkers.map((worker) => {
return Thread.terminate(worker);
navigationPathsChunks.map(async (navigationPathsChunk) => {
await runPool('lint', navigationPathsChunk);
}),
);
}

export async function initLinterWorkers() {
const navigationPaths = TocService.getNavigationPaths()
.filter((filename) => extname(filename) === '.md');
const chunkSize = getChunkSize(navigationPaths);

if (process.env.DISABLE_PARALLEL_BUILD || chunkSize < MIN_CHUNK_SIZE || WORKERS_COUNT <= 0) {
return;
}

navigationPathsChunks = splitOnChunks(navigationPaths, chunkSize).filter((arr) => arr.length);

const workersCount = navigationPathsChunks.length;
async function lintPagesFallback(navigationPaths: string[]) {
PluginService.setPlugins();

processLinterWorkers = await Promise.all(
new Array(workersCount).fill(null).map(() => {
// TODO: get linter path from env
return spawn<ProcessLinterWorker>(new Worker('./linter'), {timeout: 60000});
await Promise.all(
navigationPaths.map(async (pathToFile) => {
await lintPage({
inputPath: pathToFile,
fileExtension: extname(pathToFile),
onFinish: () => {
logger.info(pathToFile, LINTING_FINISHED);
},
});
}),
);
}

function lintPagesFallback(navigationPaths: string[]) {
PluginService.setPlugins();

navigationPaths.forEach((pathToFile) => {
lintPage({
inputPath: pathToFile,
fileExtension: extname(pathToFile),
onFinish: () => {
logger.info(pathToFile, LINTING_FINISHED);
},
});
});
}
Loading

0 comments on commit afedccc

Please sign in to comment.