Skip to content

Commit e66910d

Browse files
tyouzu1lforst
andauthored
fix: Do not delete files before all upload tasks executed (#572)
Co-authored-by: Luca Forstner <[email protected]>
1 parent c68361a commit e66910d

File tree

4 files changed

+60
-51
lines changed

4 files changed

+60
-51
lines changed

Diff for: packages/bundler-plugin-core/src/debug-id-upload.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ interface DebugIdUploadPluginOptions {
3333
silent: boolean;
3434
headers?: Record<string, string>;
3535
};
36-
freeDependencyOnSourcemapFiles: () => void;
36+
createDependencyOnSourcemapFiles: () => () => void;
3737
}
3838

3939
export function createDebugIdUploadFunction({
@@ -47,15 +47,21 @@ export function createDebugIdUploadFunction({
4747
sentryClient,
4848
sentryCliOptions,
4949
rewriteSourcesHook,
50-
freeDependencyOnSourcemapFiles,
50+
createDependencyOnSourcemapFiles,
5151
}: DebugIdUploadPluginOptions) {
52+
const freeGlobalDependencyOnSourcemapFiles = createDependencyOnSourcemapFiles();
53+
5254
return async (buildArtifactPaths: string[]) => {
5355
const artifactBundleUploadTransaction = sentryHub.startTransaction({
5456
name: "debug-id-sourcemap-upload",
5557
});
5658

5759
let folderToCleanUp: string | undefined;
5860

61+
// It is possible that this writeBundle hook (which calls this function) is called multiple times in one build (for example when reusing the plugin, or when using build tooling like `@vitejs/plugin-legacy`)
62+
// Therefore we need to actually register the execution of this hook as dependency on the sourcemap files.
63+
const freeUploadDependencyOnSourcemapFiles = createDependencyOnSourcemapFiles();
64+
5965
try {
6066
const mkdtempSpan = artifactBundleUploadTransaction.startChild({ description: "mkdtemp" });
6167
const tmpUploadFolder = await fs.promises.mkdtemp(
@@ -194,7 +200,8 @@ export function createDebugIdUploadFunction({
194200
cleanupSpan.finish();
195201
}
196202
artifactBundleUploadTransaction.finish();
197-
freeDependencyOnSourcemapFiles();
203+
freeGlobalDependencyOnSourcemapFiles();
204+
freeUploadDependencyOnSourcemapFiles();
198205
await safeFlushTelemetry(sentryClient);
199206
}
200207
};

Diff for: packages/bundler-plugin-core/src/index.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ export function sentryUnpluginFactory({
212212

213213
/**
214214
* Returns a Promise that resolves when all the currently active dependencies are freed again.
215+
*
216+
* It is very important that this function is called as late as possible before wanting to await the Promise to give
217+
* the dependency producers as much time as possible to register themselves.
215218
*/
216219
function waitUntilSourcemapFileDependenciesAreFreed() {
217220
return new Promise<void>((resolve) => {
@@ -342,7 +345,7 @@ export function sentryUnpluginFactory({
342345
vcsRemote: options.release.vcsRemote,
343346
headers: options.headers,
344347
},
345-
freeDependencyOnSourcemapFiles: createDependencyOnSourcemapFiles(),
348+
createDependencyOnSourcemapFiles,
346349
})
347350
);
348351
}
@@ -367,7 +370,7 @@ export function sentryUnpluginFactory({
367370
createDebugIdUploadFunction({
368371
assets: options.sourcemaps?.assets,
369372
ignore: options.sourcemaps?.ignore,
370-
freeDependencyOnSourcemapFiles: createDependencyOnSourcemapFiles(),
373+
createDependencyOnSourcemapFiles,
371374
dist: options.release.dist,
372375
releaseName: options.release.name,
373376
logger: logger,
@@ -405,9 +408,7 @@ export function sentryUnpluginFactory({
405408

406409
plugins.push(
407410
fileDeletionPlugin({
408-
// It is very important that this is only called after all other dependencies have been created with `createDependencyOnSourcemapFiles`.
409-
// Ideally, we always register this plugin last.
410-
dependenciesAreFreedPromise: waitUntilSourcemapFileDependenciesAreFreed(),
411+
waitUntilSourcemapFileDependenciesAreFreed,
411412
filesToDeleteAfterUpload:
412413
options.sourcemaps?.filesToDeleteAfterUpload ??
413414
options.sourcemaps?.deleteFilesAfterUpload,

Diff for: packages/bundler-plugin-core/src/plugins/release-management.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface ReleaseManagementPluginOptions {
2727
silent: boolean;
2828
headers?: Record<string, string>;
2929
};
30-
freeDependencyOnSourcemapFiles: () => void;
30+
createDependencyOnSourcemapFiles: () => () => void;
3131
}
3232

3333
export function releaseManagementPlugin({
@@ -42,11 +42,17 @@ export function releaseManagementPlugin({
4242
sentryHub,
4343
sentryClient,
4444
sentryCliOptions,
45-
freeDependencyOnSourcemapFiles,
45+
createDependencyOnSourcemapFiles,
4646
}: ReleaseManagementPluginOptions): UnpluginOptions {
47+
const freeGlobalDependencyOnSourcemapFiles = createDependencyOnSourcemapFiles();
4748
return {
4849
name: "sentry-debug-id-upload-plugin",
4950
async writeBundle() {
51+
// It is possible that this writeBundle hook is called multiple times in one build (for example when reusing the plugin, or when using build tooling like `@vitejs/plugin-legacy`)
52+
// Therefore we need to actually register the execution of this hook as dependency on the sourcemap files.
53+
const freeWriteBundleInvocationDependencyOnSourcemapFiles =
54+
createDependencyOnSourcemapFiles();
55+
5056
try {
5157
const cliInstance = new SentryCli(null, sentryCliOptions);
5258

@@ -90,7 +96,8 @@ export function releaseManagementPlugin({
9096
await safeFlushTelemetry(sentryClient);
9197
handleRecoverableError(e);
9298
} finally {
93-
freeDependencyOnSourcemapFiles();
99+
freeGlobalDependencyOnSourcemapFiles();
100+
freeWriteBundleInvocationDependencyOnSourcemapFiles();
94101
}
95102
},
96103
};

Diff for: packages/bundler-plugin-core/src/plugins/sourcemap-deletion.ts

+34-40
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import fs from "fs";
77

88
interface FileDeletionPlugin {
99
handleRecoverableError: (error: unknown) => void;
10-
dependenciesAreFreedPromise: Promise<void>;
10+
waitUntilSourcemapFileDependenciesAreFreed: () => Promise<void>;
1111
sentryHub: Hub;
1212
sentryClient: NodeClient;
1313
filesToDeleteAfterUpload: string | string[] | undefined;
@@ -19,52 +19,46 @@ export function fileDeletionPlugin({
1919
sentryHub,
2020
sentryClient,
2121
filesToDeleteAfterUpload,
22-
dependenciesAreFreedPromise,
22+
waitUntilSourcemapFileDependenciesAreFreed,
2323
logger,
2424
}: FileDeletionPlugin): UnpluginOptions {
25-
const writeBundle = async () => {
26-
try {
27-
if (filesToDeleteAfterUpload !== undefined) {
28-
const filePathsToDelete = await glob(filesToDeleteAfterUpload, {
29-
absolute: true,
30-
nodir: true,
31-
});
25+
return {
26+
name: "sentry-file-deletion-plugin",
27+
async writeBundle() {
28+
try {
29+
if (filesToDeleteAfterUpload !== undefined) {
30+
const filePathsToDelete = await glob(filesToDeleteAfterUpload, {
31+
absolute: true,
32+
nodir: true,
33+
});
3234

33-
logger.debug("Waiting for dependencies on generated files to be freed before deleting...");
35+
logger.debug(
36+
"Waiting for dependencies on generated files to be freed before deleting..."
37+
);
3438

35-
await dependenciesAreFreedPromise;
39+
await waitUntilSourcemapFileDependenciesAreFreed();
3640

37-
filePathsToDelete.forEach((filePathToDelete) => {
38-
logger.debug(`Deleting asset after upload: ${filePathToDelete}`);
39-
});
41+
filePathsToDelete.forEach((filePathToDelete) => {
42+
logger.debug(`Deleting asset after upload: ${filePathToDelete}`);
43+
});
4044

41-
await Promise.all(
42-
filePathsToDelete.map((filePathToDelete) =>
43-
fs.promises.rm(filePathToDelete, { force: true }).catch((e) => {
44-
// This is allowed to fail - we just don't do anything
45-
logger.debug(
46-
`An error occurred while attempting to delete asset: ${filePathToDelete}`,
47-
e
48-
);
49-
})
50-
)
51-
);
45+
await Promise.all(
46+
filePathsToDelete.map((filePathToDelete) =>
47+
fs.promises.rm(filePathToDelete, { force: true }).catch((e) => {
48+
// This is allowed to fail - we just don't do anything
49+
logger.debug(
50+
`An error occurred while attempting to delete asset: ${filePathToDelete}`,
51+
e
52+
);
53+
})
54+
)
55+
);
56+
}
57+
} catch (e) {
58+
sentryHub.captureException('Error in "sentry-file-deletion-plugin" buildEnd hook');
59+
await safeFlushTelemetry(sentryClient);
60+
handleRecoverableError(e);
5261
}
53-
} catch (e) {
54-
sentryHub.captureException('Error in "sentry-file-deletion-plugin" buildEnd hook');
55-
await safeFlushTelemetry(sentryClient);
56-
handleRecoverableError(e);
57-
}
58-
};
59-
return {
60-
name: "sentry-file-deletion-plugin",
61-
vite: {
62-
writeBundle: {
63-
sequential: true,
64-
order: "post",
65-
handler: writeBundle,
66-
},
6762
},
68-
writeBundle,
6963
};
7064
}

0 commit comments

Comments
 (0)