mirror of https://github.com/buster-so/buster.git
Merge pull request #710 from buster-so/staging
hotfix on multiple trigger tasks for download
This commit is contained in:
commit
e2a6454b33
|
@ -121,12 +121,19 @@ describe('downloadMetricFileHandler', () => {
|
||||||
organizationId: mockOrganizationId,
|
organizationId: mockOrganizationId,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify task was triggered with correct parameters
|
// Verify task was triggered with correct parameters and idempotency
|
||||||
expect(tasks.trigger).toHaveBeenCalledWith('export-metric-data', {
|
expect(tasks.trigger).toHaveBeenCalledWith(
|
||||||
metricId: mockMetricId,
|
'export-metric-data',
|
||||||
userId: mockUser.id,
|
{
|
||||||
organizationId: mockOrganizationId,
|
metricId: mockMetricId,
|
||||||
});
|
userId: mockUser.id,
|
||||||
|
organizationId: mockOrganizationId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
idempotencyKey: `export-${mockUser.id}-${mockMetricId}`,
|
||||||
|
idempotencyKeyTTL: '5m',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Verify successful response
|
// Verify successful response
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
|
|
|
@ -50,12 +50,21 @@ export async function downloadMetricFileHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Trigger the export task
|
// Trigger the export task with idempotency to prevent duplicates
|
||||||
const handle = await tasks.trigger('export-metric-data', {
|
// If the same user tries to download the same metric within 5 minutes,
|
||||||
metricId,
|
// it will return the existing task instead of creating a new one
|
||||||
userId: user.id,
|
const handle = await tasks.trigger(
|
||||||
organizationId,
|
'export-metric-data',
|
||||||
});
|
{
|
||||||
|
metricId,
|
||||||
|
userId: user.id,
|
||||||
|
organizationId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
idempotencyKey: `export-${user.id}-${metricId}`,
|
||||||
|
idempotencyKeyTTL: '5m', // 5 minutes TTL
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Poll for task completion with timeout
|
// Poll for task completion with timeout
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
|
@ -22,9 +22,9 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
||||||
setIsDownloading(true);
|
setIsDownloading(true);
|
||||||
setHasError(false);
|
setHasError(false);
|
||||||
|
|
||||||
// Create a timeout promise that rejects after 3 minutes
|
// Create a timeout promise that rejects after 2 minutes (matching backend timeout)
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
const timeoutPromise = new Promise((_, reject) => {
|
||||||
setTimeout(() => reject(new Error('Download timeout')), 3 * 60 * 1000); // 3 minutes
|
setTimeout(() => reject(new Error('Download timeout')), 2 * 60 * 1000); // 2 minutes
|
||||||
});
|
});
|
||||||
|
|
||||||
// Race between the API call and the timeout
|
// Race between the API call and the timeout
|
||||||
|
@ -36,14 +36,17 @@ export const MetricDataTruncatedWarning: React.FC<MetricDataTruncatedWarningProp
|
||||||
// Simply navigate to the download URL
|
// Simply navigate to the download URL
|
||||||
// The response-content-disposition header will force a download
|
// The response-content-disposition header will force a download
|
||||||
window.location.href = response.downloadUrl;
|
window.location.href = response.downloadUrl;
|
||||||
|
|
||||||
|
// Keep button disabled for longer since download is async
|
||||||
|
// User can click again after 5 seconds if needed
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsDownloading(false);
|
||||||
|
}, 5000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to download metric file:', error);
|
console.error('Failed to download metric file:', error);
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
} finally {
|
// Re-enable button immediately on error so user can retry
|
||||||
// Add a small delay before removing loading state since download happens async
|
setIsDownloading(false);
|
||||||
setTimeout(() => {
|
|
||||||
setIsDownloading(false);
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue