Skip to content

Commit 7832ea4

Browse files
[25.1] Prevent duplicate current_history_json calls
Uses a unique ID to prevent the resource watcher from creating multiple timeouts in a row. Also places the resource watcher in the history store as opposed to the `watchHistoryProvided` file which I have removed here. The way to test this bug was to wait for the history to stop polling, and then click on the reload button in the panel many times, which would do as many duplicate calls (because it would create several different timeouts).
1 parent ba0bf2e commit 7832ea4

10 files changed

Lines changed: 56 additions & 44 deletions

File tree

client/src/components/History/CurrentHistory/HistoryPanel.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { useHistoryStore } from "@/stores/historyStore";
1313
import { useUserStore } from "@/stores/userStore";
1414
import { type Alias, getOperatorForAlias } from "@/utils/filtering";
1515
import { setItemDragstart } from "@/utils/setDrag";
16-
import { startWatchingHistory } from "@/watch/watchHistoryProvided";
1716
1817
import { useHistoryDragDrop } from "../../../composables/historyDragDrop";
1918
@@ -329,7 +328,7 @@ function updateContentStats() {
329328
}
330329
331330
function reloadContents() {
332-
startWatchingHistory();
331+
historyStore.startWatchingHistory();
333332
}
334333
335334
function setInvisible(item: HistoryItemSummary) {

client/src/components/History/adapters/HistoryPanelProxy.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import Backbone from "backbone";
66
import { createDatasetCollection } from "components/History/model/queries";
77
import { useHistoryItemsStore } from "stores/historyItemsStore";
88
import { useHistoryStore } from "stores/historyStore";
9-
import { startWatchingHistory } from "watch/watchHistoryProvided";
109

1110
import { buildRuleCollectionModal } from "./buildCollectionModal";
1211

@@ -26,7 +25,7 @@ export class HistoryPanelProxy {
2625
};
2726

2827
// start watching the history with continuous queries
29-
startWatchingHistory();
28+
this.historyStore.startWatchingHistory();
3029
}
3130

3231
syncCurrentHistoryModel(currentHistory) {

client/src/components/RuleCollectionBuilder.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -631,12 +631,13 @@ import Select2 from "components/Select2";
631631
import UploadUtils from "components/Upload/utils";
632632
import $ from "jquery";
633633
import { getAppRoot } from "onload/loadConfig";
634+
import { mapActions } from "pinia";
634635
import _ from "underscore";
635636
import _l from "utils/localization";
636637
import Vue from "vue";
637638
639+
import { useHistoryStore } from "@/stores/historyStore";
638640
import { errorMessageAsString } from "@/utils/simple-error";
639-
import { startWatchingHistory } from "@/watch/watchHistoryProvided";
640641
641642
import GButton from "./BaseComponents/GButton.vue";
642643
import TooltipOnHover from "components/TooltipOnHover.vue";
@@ -1340,6 +1341,7 @@ export default {
13401341
}
13411342
},
13421343
methods: {
1344+
...mapActions(useHistoryStore, ["startWatchingHistory"]),
13431345
restoreRules(event) {
13441346
const json = JSON.parse(event);
13451347
this.rules = json.rules;
@@ -1458,7 +1460,7 @@ export default {
14581460
this.mapping.splice(index, 1);
14591461
},
14601462
refreshAndWait(response) {
1461-
startWatchingHistory();
1463+
this.startWatchingHistory();
14621464
this.waitOnJob(response);
14631465
},
14641466
waitOnJob(response) {
@@ -1474,7 +1476,7 @@ export default {
14741476
"Unknown error encountered while running your upload job, this could be a server issue or a problem with the upload definition.";
14751477
this.doFullJobCheck(jobId);
14761478
} else {
1477-
startWatchingHistory();
1479+
this.startWatchingHistory();
14781480
this.$emit("onCreate", jobResponse.data);
14791481
if (this.oncreate) {
14801482
// legacy non-event handling

client/src/components/Tool/ToolForm.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ import { useHistoryStore } from "@/stores/historyStore";
128128
import { useTourStore } from "@/stores/tourStore";
129129
import { useUserStore } from "@/stores/userStore";
130130
import { useUserToolsServiceCredentialsStore } from "@/stores/userToolsServiceCredentialsStore";
131-
import { startWatchingHistory } from "@/watch/watchHistoryProvided";
132131
133132
import ToolRecommendation from "../ToolRecommendation";
134133
import { getToolFormData, submitJob, updateToolFormData } from "./services";
@@ -310,6 +309,7 @@ export default {
310309
methods: {
311310
...mapActions(useJobStore, ["saveLatestResponse"]),
312311
...mapActions(useTourStore, ["setTour"]),
312+
...mapActions(useHistoryStore, ["startWatchingHistory"]),
313313
emailAllowed(config, user) {
314314
return config.server_mail_configured && !user.isAnonymous;
315315
},
@@ -428,7 +428,7 @@ export default {
428428
this.submissionRequestFailed = false;
429429
this.showExecuting = false;
430430
let changeRoute = false;
431-
startWatchingHistory();
431+
this.startWatchingHistory();
432432
if (jobResponse.produces_entry_points) {
433433
this.showEntryPoints = true;
434434
this.entryPoints = jobResponse.jobs;

client/src/components/Workflow/Run/WorkflowRunSuccess.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { computed, onMounted } from "vue";
33
44
import type { WorkflowInvocation } from "@/api/invocations";
5-
import { startWatchingHistory } from "@/watch/watchHistoryProvided";
5+
import { useHistoryStore } from "@/stores/historyStore";
66
77
import Webhook from "@/components/Common/Webhook.vue";
88
import GridInvocation from "@/components/Grid/GridInvocation.vue";
@@ -13,8 +13,10 @@ const props = defineProps<{
1313
invocations: WorkflowInvocation[];
1414
}>();
1515
16+
const historyStore = useHistoryStore();
17+
1618
onMounted(() => {
17-
startWatchingHistory();
19+
historyStore.startWatchingHistory();
1820
});
1921
2022
const targetHistories = computed(() =>

client/src/composables/resourceWatcher.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export function useResourceWatcher<T = unknown>(
4343
let currentPollingInterval = shortPollingInterval;
4444
let watchTimeout: NodeJS.Timeout | null = null;
4545
let isEventSetup = false;
46+
47+
/** ID to track the current request to prevent duplicate polling */
48+
let currentRequestId = 0;
4649
const isWatchingResource = ref<boolean>(false);
4750

4851
/**
@@ -81,19 +84,26 @@ export function useResourceWatcher<T = unknown>(
8184

8285
function stopWatcher() {
8386
isWatchingResource.value = false;
87+
88+
// Update the request ID to invalidate any in-flight requests
89+
currentRequestId++;
90+
8491
if (watchTimeout) {
8592
clearTimeout(watchTimeout);
8693
watchTimeout = null;
8794
}
8895
}
8996

9097
async function tryWatchResource(app?: T) {
98+
// Capture the current request ID to ensure we only schedule the next poll
99+
const requestId = currentRequestId;
91100
try {
92101
await watchHandler(app);
93102
} catch (error) {
94103
console.warn(error);
95104
} finally {
96-
if (currentPollingInterval && isWatchingResource.value) {
105+
// Only schedule next poll if still watching and no new requests have been made
106+
if (currentPollingInterval && isWatchingResource.value && requestId === currentRequestId) {
97107
watchTimeout = setTimeout(() => {
98108
tryWatchResource(app);
99109
}, currentPollingInterval);
@@ -113,7 +123,13 @@ export function useResourceWatcher<T = unknown>(
113123
currentPollingInterval = shortPollingInterval;
114124
startWatchingResourceIfNeeded();
115125
} else {
116-
currentPollingInterval = enableBackgroundPolling ? longPollingInterval : undefined;
126+
if (enableBackgroundPolling) {
127+
currentPollingInterval = longPollingInterval;
128+
} else {
129+
// Stop watching when tab is not visible and background polling is disabled
130+
currentPollingInterval = undefined;
131+
stopWatchingResourceIfNeeded();
132+
}
117133
}
118134
}
119135

client/src/stores/historyStore.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import {
1212
} from "@/api";
1313
import type { UpdateHistoryPayload } from "@/api/histories";
1414
import type { ArchivedHistoryDetailed } from "@/api/histories.archived";
15+
import { getGalaxyInstance } from "@/app";
1516
import { HistoryFilters } from "@/components/History/HistoryFilters";
17+
import { useResourceWatcher } from "@/composables/resourceWatcher";
1618
import { useUserLocalStorage } from "@/composables/userLocalStorage";
1719
import {
1820
createAndSelectNewHistory,
@@ -25,6 +27,11 @@ import {
2527
} from "@/stores/services/history.services";
2628
import { rethrowSimple } from "@/utils/simple-error";
2729
import { sortByObjectProp } from "@/utils/sorting";
30+
import {
31+
ACTIVE_POLLING_INTERVAL,
32+
INACTIVE_POLLING_INTERVAL,
33+
watchHistory as watchHistorySuppliedApp,
34+
} from "@/watch/watchHistory";
2835

2936
const PAGINATION_LIMIT = 10;
3037
const isLoadingHistory = new Set();
@@ -356,6 +363,19 @@ export const useHistoryStore = defineStore("historyStore", () => {
356363
}
357364
}
358365

366+
function watchHistory() {
367+
const app = getGalaxyInstance();
368+
return watchHistorySuppliedApp(app);
369+
}
370+
371+
const { startWatchingResource: startWatchingHistory, isWatchingResource: isWatchingHistory } = useResourceWatcher(
372+
watchHistory,
373+
{
374+
shortPollingInterval: ACTIVE_POLLING_INTERVAL,
375+
longPollingInterval: INACTIVE_POLLING_INTERVAL,
376+
},
377+
);
378+
359379
async function loadHistoryById(historyId: string): Promise<HistorySummaryExtended | undefined> {
360380
if (!isLoadingHistory.has(historyId)) {
361381
isLoadingHistory.add(historyId);
@@ -475,6 +495,8 @@ export const useHistoryStore = defineStore("historyStore", () => {
475495
restoreHistory,
476496
restoreHistories,
477497
handleTotalCountChange,
498+
startWatchingHistory,
499+
isWatchingHistory,
478500
loadCurrentHistory,
479501
loadHistories,
480502
loadHistoryById,

client/src/utils/data.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useGlobalUploadModal } from "composables/globalUploadModal";
22

3+
import { useHistoryStore } from "@/stores/historyStore";
34
import { uploadPayload } from "@/utils/upload-payload.js";
45
import { uploadSubmit } from "@/utils/upload-submit.js";
5-
import { startWatchingHistory } from "@/watch/watchHistory";
66

77
import { getCurrentGalaxyHistory, mountSelectionDialog } from "./dataModalUtils";
88

@@ -41,7 +41,8 @@ export function create(galaxy, options) {
4141
getHistory().then((history_id) => {
4242
uploadSubmit({
4343
success: (response) => {
44-
startWatchingHistory(galaxy);
44+
const historyStore = useHistoryStore();
45+
historyStore.startWatchingHistory();
4546
if (options.success) {
4647
options.success(response);
4748
}

client/src/watch/watchHistory.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { useHistoryStore } from "stores/historyStore";
1111
import { loadSet } from "utils/setCache";
1212
import { urlData } from "utils/url";
1313

14-
import { useResourceWatcher } from "@/composables/resourceWatcher";
1514
import { useCollectionElementsStore } from "@/stores/collectionElementsStore";
1615
import { useDatasetStore } from "@/stores/datasetStore";
1716

@@ -26,13 +25,6 @@ let lastUpdateTime = null;
2625
// last time changed history items have been requested
2726
let lastRequestDate = new Date();
2827

29-
const { startWatchingResource: startWatchingHistory } = useResourceWatcher(watchHistory, {
30-
shortPollingInterval: ACTIVE_POLLING_INTERVAL,
31-
longPollingInterval: INACTIVE_POLLING_INTERVAL,
32-
});
33-
34-
export { startWatchingHistory };
35-
3628
export async function watchHistory(app) {
3729
// GalaxyApp
3830
const { isWatching } = storeToRefs(useHistoryItemsStore());

client/src/watch/watchHistoryProvided.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)