Skip to content

Commit 20b4eca

Browse files
authored
Merge b2a31f8 into 7734c0e
2 parents 7734c0e + b2a31f8 commit 20b4eca

20 files changed

+94
-4
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

@@ -1027,6 +1029,10 @@ export default class RequestTracker {
10271029
farm: WorkerFarm;
10281030
options: ParcelOptions;
10291031
signal: ?AbortSignal;
1032+
incompleteRequests: Map<
1033+
Request<mixed, mixed>['id'],
1034+
{|deferred: Deferred<void>, promise: Promise<void>, timerId: TimeoutID|},
1035+
> = new Map();
10301036

10311037
constructor({
10321038
graph,
@@ -1160,11 +1166,63 @@ export default class RequestTracker {
11601166
this.graph.replaceSubrequests(requestNodeId, subrequestContextKeys);
11611167
}
11621168

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

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

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

7172
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() {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import path from 'path';
44
import {distDir, bundle, outputFS} from '@parcel/test-utils';
55

66
describe('tracing', function () {
7-
it('should produce a trace', async function () {
7+
it.only('should produce a trace', async function () {
88
await bundle(
99
path.join(__dirname, '/integration/typescript-jsx/index.tsx'),
1010
{

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import nullthrows from 'nullthrows';
1616
const inputDir = path.join(__dirname, '/input');
1717

1818
describe('transpilation', function () {
19-
it('should not transpile if no targets are defined', async function () {
19+
it.only('should not transpile if no targets are defined', async function () {
2020
await bundle(path.join(__dirname, '/integration/babel-default/index.js'), {
2121
defaultTargetOptions: {
2222
engines: undefined,

0 commit comments

Comments
 (0)