Skip to content

Commit e96d41c

Browse files
authored
Merge 26b48e9 into 4cd9467
2 parents 4cd9467 + 26b48e9 commit e96d41c

18 files changed

+92
-2
lines changed

packages/core/core/src/RequestTracker.js

+62-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import {report} from './ReporterRunner';
5454
import {PromiseQueue} from '@parcel/utils';
5555
import type {Cache} from '@parcel/cache';
5656
import {getConfigKeyContentHash} from './requests/ConfigRequest';
57+
import {getFeatureFlag} from '@parcel/feature-flags';
5758

5859
export const requestGraphEdgeTypes = {
5960
subrequest: 2,
@@ -132,6 +133,7 @@ type Request<TInput, TResult> = {|
132133
id: string,
133134
+type: RequestType,
134135
input: TInput,
136+
incompleteRequest?: boolean,
135137
run: ({|input: TInput, ...StaticRunOpts<TResult>|}) => Async<TResult>,
136138
|};
137139

@@ -1029,6 +1031,10 @@ export default class RequestTracker {
10291031
options: ParcelOptions;
10301032
signal: ?AbortSignal;
10311033
stats: Map<RequestType, number> = new Map();
1034+
incompleteRequests: Map<
1035+
Request<mixed, mixed>['id'],
1036+
{|deferred: Deferred<void>, promise: Promise<void>, timerId: TimeoutID|},
1037+
> = new Map();
10321038

10331039
constructor({
10341040
graph,
@@ -1162,11 +1168,63 @@ export default class RequestTracker {
11621168
this.graph.replaceSubrequests(requestNodeId, subrequestContextKeys);
11631169
}
11641170

1171+
flushCachedRequest(requestId: ContentKey) {
1172+
let existingPromise = this.incompleteRequests.get(requestId);
1173+
1174+
if (existingPromise) {
1175+
logger.verbose({
1176+
origin: '@parcel/core',
1177+
message: 'Incomplete request promise resolved',
1178+
meta: {trackableEvent: 'incomplete_promise_resolved'},
1179+
});
1180+
1181+
clearTimeout(existingPromise.timerId);
1182+
existingPromise.deferred.resolve();
1183+
}
1184+
}
1185+
1186+
waitForFullRequest(requestId: ContentKey): Promise<void> {
1187+
let existingPromise = this.incompleteRequests.get(requestId);
1188+
1189+
if (existingPromise) {
1190+
return existingPromise.promise;
1191+
}
1192+
1193+
let deferredPromise = makeDeferredWithPromise();
1194+
1195+
let timerId = setTimeout(() => {
1196+
logger.verbose({
1197+
origin: '@parcel/core',
1198+
message: 'Incomplete request promise timed out',
1199+
meta: {trackableEvent: 'incomplete_promise_timeout'},
1200+
});
1201+
deferredPromise.deferred.resolve();
1202+
}, 5_000);
1203+
1204+
this.incompleteRequests.set(requestId, {...deferredPromise, timerId});
1205+
1206+
return deferredPromise.promise;
1207+
}
1208+
11651209
async runRequest<TInput, TResult>(
11661210
request: Request<TInput, TResult>,
11671211
opts?: ?RunRequestOpts,
11681212
): Promise<TResult> {
1169-
let requestId = this.graph.hasContentKey(request.id)
1213+
let hasKey = this.graph.hasContentKey(request.id);
1214+
1215+
if (
1216+
request.incompleteRequest &&
1217+
!hasKey &&
1218+
getFeatureFlag('devDepRequestBugFix')
1219+
) {
1220+
// To avoid possible race conditions with the worker farm build cache, we
1221+
// suspend processing of an incomplete request until the full details are back
1222+
// from another worker.
1223+
await this.waitForFullRequest(request.id);
1224+
hasKey = this.graph.hasContentKey(request.id);
1225+
}
1226+
1227+
let requestId = hasKey
11701228
? this.graph.getNodeIdByContentKey(request.id)
11711229
: undefined;
11721230
let hasValidResult = requestId != null && this.hasValidResult(requestId);
@@ -1228,6 +1286,9 @@ export default class RequestTracker {
12281286
deferred.resolve(false);
12291287
throw err;
12301288
} finally {
1289+
if (getFeatureFlag('devDepRequestBugFix')) {
1290+
this.flushCachedRequest(request.id);
1291+
}
12311292
this.graph.replaceSubrequests(requestNodeId, [...subRequestContentKeys]);
12321293
}
12331294
}

packages/core/core/src/requests/AssetGraphRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type AssetGraphRequest = {|
6767
+type: typeof requestTypes.asset_graph_request,
6868
run: RunInput => Async<AssetGraphRequestResult>,
6969
input: AssetGraphRequestInput,
70+
incompleteRequest?: boolean,
7071
|};
7172

7273
export default function createAssetGraphRequest(

packages/core/core/src/requests/AssetRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type AssetRequest = {|
3232
+type: typeof requestTypes.asset_request,
3333
run: (RunInput<AssetRequestResult>) => Async<AssetRequestResult>,
3434
input: AssetRequestInput,
35+
incompleteRequest?: boolean,
3536
|};
3637

3738
export default function createAssetRequest(

packages/core/core/src/requests/BundleGraphRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type BundleGraphRequest = {|
8282
+type: typeof requestTypes.bundle_graph_request,
8383
run: RunInput => Async<BundleGraphResult>,
8484
input: BundleGraphRequestInput,
85+
incompleteRequest?: boolean,
8586
|};
8687

8788
export default function createBundleGraphRequest(

packages/core/core/src/requests/DevDepRequest.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,22 @@ export async function runDevDepRequest<TResult>(
190190
await api.runRequest<null, DevDepRequestResult | void>({
191191
id: 'dev_dep_request:' + devDepRequest.specifier + ':' + devDepRequest.hash,
192192
type: requestTypes.dev_dep_request,
193+
incompleteRequest: !(
194+
devDepRequest.invalidateOnFileChange &&
195+
devDepRequest.invalidateOnFileCreate
196+
),
193197
run: ({api}) => {
194-
for (let filePath of nullthrows(devDepRequest.invalidateOnFileChange)) {
198+
for (let filePath of nullthrows(
199+
devDepRequest.invalidateOnFileChange,
200+
'DevDepRequest missing invalidateOnFileChange',
201+
)) {
195202
api.invalidateOnFileUpdate(filePath);
196203
api.invalidateOnFileDelete(filePath);
197204
}
198205

199206
for (let invalidation of nullthrows(
200207
devDepRequest.invalidateOnFileCreate,
208+
'DevDepRequest missing invalidateOnFileCreate',
201209
)) {
202210
api.invalidateOnFileCreate(invalidation);
203211
}

packages/core/core/src/requests/EntryRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type EntryRequest = {|
3636
+type: typeof requestTypes.entry_request,
3737
run: (RunOpts<EntryResult>) => Async<EntryResult>,
3838
input: ProjectPath,
39+
incompleteRequest?: boolean,
3940
|};
4041

4142
export type EntryResult = {|

packages/core/core/src/requests/PackageRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export type PackageRequest = {|
3434
+type: typeof requestTypes.package_request,
3535
run: (RunInput<BundleInfo>) => Async<BundleInfo>,
3636
input: PackageRequestInput,
37+
incompleteRequest?: boolean,
3738
|};
3839

3940
export function createPackageRequest(

packages/core/core/src/requests/ParcelBuildRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export type ParcelBuildRequest = {|
4646
+type: typeof requestTypes.parcel_build_request,
4747
run: (RunInput<ParcelBuildRequestResult>) => Async<ParcelBuildRequestResult>,
4848
input: ParcelBuildRequestInput,
49+
incompleteRequest?: boolean,
4950
|};
5051

5152
export default function createParcelBuildRequest(

packages/core/core/src/requests/ParcelConfigRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export type ParcelConfigRequest = {|
5656
type: typeof requestTypes.parcel_config_request,
5757
input: null,
5858
run: (RunOpts<ConfigAndCachePath>) => Async<ConfigAndCachePath>,
59+
incompleteRequest?: boolean,
5960
|};
6061

6162
type ParcelConfigChain = {|

packages/core/core/src/requests/PathRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export type PathRequest = {|
5858
+type: typeof requestTypes.path_request,
5959
run: (RunOpts<?AssetGroup>) => Async<?AssetGroup>,
6060
input: PathRequestInput,
61+
incompleteRequest?: boolean,
6162
|};
6263

6364
export type PathRequestInput = {|

packages/core/core/src/requests/TargetRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export type TargetRequest = {|
9393
+type: typeof requestTypes.target_request,
9494
run: (RunOpts<Array<Target>>) => Async<Array<Target>>,
9595
input: Entry,
96+
incompleteRequest?: boolean,
9697
|};
9798

9899
const type = 'target_request';

packages/core/core/src/requests/ValidationRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type ValidationRequest = {|
1717
+type: typeof requestTypes.validation_request,
1818
run: (RunOpts<void>) => Async<void>,
1919
input: ValidationRequestInput,
20+
incompleteRequest?: boolean,
2021
|};
2122

2223
type RunOpts<TResult> = {|

packages/core/core/src/requests/WriteBundleRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export type WriteBundleRequest = {|
6161
+type: typeof requestTypes.write_bundle_request,
6262
run: (RunInput<PackagedBundleInfo>) => Async<PackagedBundleInfo>,
6363
input: WriteBundleRequestInput,
64+
incompleteRequest?: boolean,
6465
|};
6566

6667
/**

packages/core/core/src/requests/WriteBundlesRequest.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type WriteBundlesRequest = {|
3333
RunInput<Map<string, PackagedBundleInfo>>,
3434
) => Async<Map<string, PackagedBundleInfo>>,
3535
input: WriteBundlesRequestInput,
36+
incompleteRequest?: boolean,
3637
|};
3738

3839
/**

packages/core/core/test/test-utils.js

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const DEFAULT_OPTIONS: ParcelOptions = {
5353
},
5454
featureFlags: {
5555
exampleFeature: false,
56+
devDepRequestBugFix: false,
5657
configKeyInvalidation: false,
5758
},
5859
};

packages/core/feature-flags/src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type FeatureFlags = _FeatureFlags;
88
export const DEFAULT_FEATURE_FLAGS: FeatureFlags = {
99
exampleFeature: false,
1010
configKeyInvalidation: false,
11+
devDepRequestBugFix: false,
1112
};
1213

1314
let featureFlagValues: FeatureFlags = {...DEFAULT_FEATURE_FLAGS};

packages/core/feature-flags/src/types.js

+4
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ export type FeatureFlags = {|
99
* `config.getConfigFrom(..., {packageKey: '...'})` and the value itself hasn't changed.
1010
*/
1111
+configKeyInvalidation: boolean,
12+
/**
13+
* Enable experimental fix for the DevDepRequest build cache bug
14+
*/
15+
+devDepRequestBugFix: boolean,
1216
|};

packages/core/integration-tests/test/cache.js

+3
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,7 @@ describe('cache', function () {
13181318
let b = await testCache({
13191319
featureFlags: {
13201320
exampleFeature: false,
1321+
devDepRequestBugFix: false,
13211322
configKeyInvalidation: true,
13221323
},
13231324
async setup() {
@@ -1378,6 +1379,7 @@ describe('cache', function () {
13781379
let b = await testCache({
13791380
featureFlags: {
13801381
exampleFeature: false,
1382+
devDepRequestBugFix: false,
13811383
configKeyInvalidation: true,
13821384
},
13831385
async setup() {
@@ -1438,6 +1440,7 @@ describe('cache', function () {
14381440
let b = await testCache({
14391441
featureFlags: {
14401442
exampleFeature: false,
1443+
devDepRequestBugFix: false,
14411444
configKeyInvalidation: true,
14421445
},
14431446
async setup() {

0 commit comments

Comments
 (0)