Skip to content

Commit 13be95a

Browse files
committed
Semantic cleanup
1 parent d0f4d9c commit 13be95a

3 files changed

Lines changed: 41 additions & 45 deletions

File tree

‎apps/rush-lib/src/logic/operations/AsyncOperationQueue.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ export class AsyncOperationQueue
6969
} else if (operation.dependencies.size === 0) {
7070
// This task is ready to process, hand it to the iterator.
7171
queue.splice(i, 1);
72-
waitingIterators.pop()!({
72+
// Needs to have queue semantics, otherwise tools that iterate it get confused
73+
waitingIterators.shift()!({
7374
value: operation,
7475
done: false
7576
});

‎apps/rush-lib/src/logic/operations/OperationExecutionManager.ts‎

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import {
1010
TextRewriterTransform
1111
} from '@rushstack/terminal';
1212
import { StreamCollator, CollatedTerminal, CollatedWriter } from '@rushstack/stream-collator';
13-
import { AlreadyReportedError, NewlineKind, InternalError, Sort } from '@rushstack/node-core-library';
13+
import { AlreadyReportedError, NewlineKind, InternalError, Sort, Async } from '@rushstack/node-core-library';
1414

1515
import { AsyncOperationQueue, IOperationSortFunction } from './AsyncOperationQueue';
1616
import { Operation } from './Operation';
1717
import { OperationStatus } from './OperationStatus';
1818
import { IOperationExecutionRecordContext, OperationExecutionRecord } from './OperationExecutionRecord';
19-
import { OperationError } from './OperationError';
2019

2120
export interface IOperationExecutionManagerOptions {
2221
quietMode: boolean;
@@ -205,18 +204,22 @@ export class OperationExecutionManager {
205204
};
206205
const executionQueue: AsyncOperationQueue = new AsyncOperationQueue(this._executionRecords, prioritySort);
207206

208-
// Iterate in parallel with maxParallelism concurrent lanes
209-
await Promise.all(
210-
Array.from({ length: maxParallelism }, async (unused: undefined, index: number): Promise<void> => {
211-
// laneId can be used in logging to examine concurrency
212-
const laneId: number = index + 1;
213-
// The executionQueue is a singular async iterable that stalls until an operation is available, and marks itself
214-
// done when the queue is empty.
215-
for await (const operations of executionQueue) {
216-
// Take an operation, execute it, wait for it to finish, wait for a new operations
217-
await this._executeOperationAsync(operations, laneId);
218-
}
219-
})
207+
// This function is a callback because it may write to the collatedWriter before
208+
// operation.executeAsync returns (and cleans up the writer)
209+
const onOperationComplete: (record: OperationExecutionRecord) => void = (
210+
record: OperationExecutionRecord
211+
) => {
212+
this._onOperationComplete(record);
213+
};
214+
215+
await Async.forEachAsync(
216+
executionQueue,
217+
async (operation: OperationExecutionRecord) => {
218+
await operation.executeAsync(onOperationComplete);
219+
},
220+
{
221+
concurrency: maxParallelism
222+
}
220223
);
221224

222225
this._printOperationStatus();
@@ -230,40 +233,18 @@ export class OperationExecutionManager {
230233
}
231234
}
232235

233-
private async _executeOperationAsync(operation: OperationExecutionRecord, tid: number): Promise<void> {
234-
let result: OperationStatus = (operation.status = OperationStatus.Executing);
235-
operation.stopwatch.start();
236-
237-
try {
238-
result = await operation.runner.executeAsync(operation);
239-
240-
// Only perform global state updates. Internal state updates are handled by Operation itself.
241-
this._handleOperationResult(operation, result);
242-
} catch (error) {
243-
const status: OperationStatus = OperationStatus.Failure;
244-
operation.error = error as OperationError;
245-
this._handleOperationResult(operation, status);
246-
} finally {
247-
// Delegate cleanup.
248-
// Calling `operation.collatedWriter` creates it if it didn't exist.
249-
operation.finish();
250-
}
251-
}
252-
253236
/**
254-
* Applies the new status to an OperationExecutionRecord and propagates any relevant effects.
237+
* Handles the result of the operation and propagates any relevant effects.
255238
*/
256-
private _handleOperationResult(record: OperationExecutionRecord, result: OperationStatus): void {
257-
record.status = result;
258-
259-
const { runner, name } = record;
239+
private _onOperationComplete(record: OperationExecutionRecord): void {
240+
const { runner, name, status } = record;
260241

261242
let blockCacheWrite: boolean = !runner.isCacheWriteAllowed;
262243
let blockSkip: boolean = !runner.isSkipAllowed;
263244

264245
const silent: boolean = runner.silent;
265246

266-
switch (result) {
247+
switch (status) {
267248
/**
268249
* This operation failed. Mark it as such and all reachable dependents as blocked.
269250
*/

‎apps/rush-lib/src/logic/operations/OperationExecutionRecord.ts‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,23 @@ export class OperationExecutionRecord implements IOperationRunnerContext {
111111
return this._collatedWriter;
112112
}
113113

114-
public finish(): void {
115-
this._collatedWriter?.close();
116-
this.stdioSummarizer.close();
117-
this.stopwatch.stop();
114+
public async executeAsync(onResult: (record: OperationExecutionRecord) => void): Promise<void> {
115+
this.status = OperationStatus.Executing;
116+
this.stopwatch.start();
117+
118+
try {
119+
this.status = await this.runner.executeAsync(this);
120+
// Delegate global state reporting
121+
onResult(this);
122+
} catch (error) {
123+
this.status = OperationStatus.Failure;
124+
this.error = error as OperationError;
125+
// Delegate global state reporting
126+
onResult(this);
127+
} finally {
128+
this._collatedWriter?.close();
129+
this.stdioSummarizer.close();
130+
this.stopwatch.stop();
131+
}
118132
}
119133
}

0 commit comments

Comments
 (0)