fix(imports): ignore stale detail polls after retry
This commit is contained in:
@@ -36,6 +36,7 @@ const errorsOpen = ref(true);
|
||||
const skipLogsOpen = ref(true);
|
||||
let pollTimer;
|
||||
let isPageActive = false;
|
||||
let importRequestVersion = 0;
|
||||
|
||||
const hasActiveImport = computed(() => isActiveImport(dataImport.value));
|
||||
|
||||
@@ -51,6 +52,7 @@ const fetchImport = async ({
|
||||
manual = false,
|
||||
requestedSkipLogsType = selectedSkipLogsType.value,
|
||||
} = {}) => {
|
||||
const requestVersion = importRequestVersion;
|
||||
if (showLoader) {
|
||||
isLoading.value = true;
|
||||
} else if (manual) {
|
||||
@@ -61,6 +63,8 @@ const fetchImport = async ({
|
||||
const response = await DataImportsAPI.show(route.params.dataImportId, {
|
||||
skip_logs_type: requestedSkipLogsType || undefined,
|
||||
});
|
||||
if (requestVersion !== importRequestVersion) return;
|
||||
|
||||
dataImport.value = response.data;
|
||||
selectedSkipLogsType.value =
|
||||
response.data.skip_logs_filters?.selected_source_object_type ||
|
||||
@@ -106,6 +110,13 @@ const refreshImportInBackground = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const startPolling = () => {
|
||||
stopPolling();
|
||||
if (!isPageActive || !hasActiveImport.value) return;
|
||||
|
||||
pollTimer = window.setInterval(refreshImportInBackground, POLL_INTERVAL_MS);
|
||||
};
|
||||
|
||||
const abandonImport = async () => {
|
||||
isAbandoning.value = true;
|
||||
try {
|
||||
@@ -120,6 +131,8 @@ const abandonImport = async () => {
|
||||
|
||||
const retryImport = async () => {
|
||||
isRetrying.value = true;
|
||||
importRequestVersion += 1;
|
||||
stopPolling();
|
||||
try {
|
||||
const response = await DataImportsAPI.retry(dataImport.value.id);
|
||||
dataImport.value = response.data;
|
||||
@@ -128,6 +141,7 @@ const retryImport = async () => {
|
||||
useAlert(t('DATA_IMPORTS.ALERTS.IMPORT_RETRY_FAILED'));
|
||||
} finally {
|
||||
isRetrying.value = false;
|
||||
if (hasActiveImport.value) startPolling();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -164,13 +178,6 @@ const downloadSkipLogs = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const startPolling = () => {
|
||||
stopPolling();
|
||||
if (!isPageActive || !hasActiveImport.value) return;
|
||||
|
||||
pollTimer = window.setInterval(refreshImportInBackground, POLL_INTERVAL_MS);
|
||||
};
|
||||
|
||||
const handleVisibilityChange = () => {
|
||||
if (isPageActive && !document.hidden && hasActiveImport.value) {
|
||||
refreshImportInBackground();
|
||||
|
||||
@@ -3,6 +3,7 @@ import { KeepAlive, defineComponent, h, nextTick } from 'vue';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import DataImportsAPI from 'dashboard/api/dataImports';
|
||||
import Show from '../Show.vue';
|
||||
import { POLL_INTERVAL_MS } from '../importStatus';
|
||||
|
||||
vi.mock('dashboard/api/dataImports', () => ({
|
||||
default: {
|
||||
@@ -35,8 +36,28 @@ const SettingsLayoutStub = {
|
||||
|
||||
const ImportDetailHeaderStub = {
|
||||
name: 'ImportDetailHeader',
|
||||
props: {
|
||||
dataImport: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['retry'],
|
||||
template: '<button data-test="retry" @click="$emit(\'retry\')" />',
|
||||
template: `
|
||||
<button
|
||||
v-if="dataImport?.stalled"
|
||||
data-test="retry"
|
||||
@click="$emit('retry')"
|
||||
/>
|
||||
`,
|
||||
};
|
||||
|
||||
const deferredRequest = () => {
|
||||
let resolve;
|
||||
const promise = new Promise(resolvePromise => {
|
||||
resolve = resolvePromise;
|
||||
});
|
||||
return { promise, resolve };
|
||||
};
|
||||
|
||||
const mountShow = () => {
|
||||
@@ -101,4 +122,40 @@ describe('data import detail actions', () => {
|
||||
expect(useAlert).toHaveBeenCalledWith('DATA_IMPORTS.ALERTS.IMPORT_RETRIED');
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it('ignores an older poll response after retry succeeds', async () => {
|
||||
const pollRequest = deferredRequest();
|
||||
DataImportsAPI.retry.mockResolvedValue({
|
||||
data: {
|
||||
id: 1,
|
||||
status: 'pending',
|
||||
stalled: false,
|
||||
skip_logs_filters: {},
|
||||
},
|
||||
});
|
||||
const wrapper = mountShow();
|
||||
await nextTick();
|
||||
await flushPromises();
|
||||
|
||||
DataImportsAPI.show.mockReturnValueOnce(pollRequest.promise);
|
||||
await vi.advanceTimersByTimeAsync(POLL_INTERVAL_MS);
|
||||
expect(DataImportsAPI.show).toHaveBeenCalledTimes(2);
|
||||
|
||||
await wrapper.find('[data-test="retry"]').trigger('click');
|
||||
await flushPromises();
|
||||
expect(wrapper.find('[data-test="retry"]').exists()).toBe(false);
|
||||
|
||||
pollRequest.resolve({
|
||||
data: {
|
||||
id: 1,
|
||||
status: 'processing',
|
||||
stalled: true,
|
||||
skip_logs_filters: {},
|
||||
},
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.find('[data-test="retry"]').exists()).toBe(false);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user