mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-20 06:37:23 +02:00
perf: bound request work and resource usage (#866)
* perf: bound request work and resource usage * fix: address performance review regressions * fix: guard content expiration and dashboard state * fix: tolerate cache outages and retire derived paths * fix: revalidate expiration claims and status pagination * fix: retry interrupted repository metadata cleanup * fix: retire obsolete content cache storage * fix: activate tree metadata and recheck expiration claims * fix: fence cache publication across expiration * fix: recover staged trees and enforce cache lifecycle cleanup * fix: prune expired transforms during database outages * fix: finish conference removals and reload expiration candidates
This commit is contained in:
1 parent
32722169a2
commit
6434337923
74 files changed
+4752
-553
No files matched your search
+90
-16
@@ -461,7 +461,8 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
state.nameMessage = "";
|
||||
state.needsAttention = item => item.status === "error" || item._broken
|
||||
|| (statusKey(item.status) === "progress" && item._stale);
|
||||
state.attentionCount = () => state.items.filter(state.needsAttention).length;
|
||||
state.attentionCount = () => state.dashboardTotals?.attention ?? state.items.filter(state.needsAttention).length;
|
||||
state.hasProjects = () => (state.dashboardTotals?.total ?? state.items.length) > 0;
|
||||
state.setProjectView = view => {
|
||||
state.projectView = view;
|
||||
if (view === "attention") {
|
||||
@@ -496,6 +497,13 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
item.projectName = res.data.name;
|
||||
item._label = item.projectName || item._fallbackLabel;
|
||||
if (state.selectedProject === item) state.nameMessage = name ? "Project name saved." : "Default project name restored.";
|
||||
if (!legacyDashboard) {
|
||||
state.dashboardCursor = null;
|
||||
await loadAll();
|
||||
if (state.selectedProject === item) {
|
||||
state.selectedProject = state.items.find(current => current._type === item._type && current._id === item._id) || null;
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
if (state.selectedProject === item) state.nameError = "The project name could not be saved. Try again.";
|
||||
} finally { state.nameSaving = false; }
|
||||
@@ -681,7 +689,7 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
|
||||
// All three lists load in parallel and are merged once, so the table
|
||||
// does not re-sort three times while it fills in.
|
||||
function loadAll() {
|
||||
function loadLegacy() {
|
||||
state.loading = true;
|
||||
return promises
|
||||
.all([
|
||||
@@ -740,6 +748,55 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
let dashboardGeneration = 0;
|
||||
let legacyDashboard = false;
|
||||
state.dashboardCursor = null;
|
||||
state.dashboardError = "";
|
||||
function decorateSummary(item) {
|
||||
const src = item.source || {};
|
||||
if (item._type === "repo") return decorateItem(item, item.repoId, item.repoId, src.fullName, "/anonymize/" + item.repoId, "/r/" + item.repoId + "/");
|
||||
if (item._type === "pr") return decorateItem(item, item.pullRequestId, item.pullRequestId,
|
||||
src.repositoryFullName ? src.repositoryFullName + "#" + src.pullRequestId : undefined,
|
||||
"/pull-request-anonymize/" + item.pullRequestId, "/pr/" + item.pullRequestId + "/");
|
||||
return decorateItem(item, item.gistId, item.gistId, src.gistId, "/gist-anonymize/" + item.gistId, "/gist/" + item.gistId + "/");
|
||||
}
|
||||
function loadAll(append = false) {
|
||||
if (legacyDashboard) return loadLegacy();
|
||||
const generation = ++dashboardGeneration;
|
||||
state.loading = !append;
|
||||
state.loadingMore = append;
|
||||
state.dashboardError = "";
|
||||
return http.get("/api/user/dashboard", { params: {
|
||||
q: state.search, type: state.typeFilter, sort: state.orderBy,
|
||||
statuses: Object.keys(state.filters.status).filter(key => state.filters.status[key] !== false).join(",") || "none",
|
||||
attention: String(state.projectView === "attention"),
|
||||
cursor: append ? state.dashboardCursor : undefined,
|
||||
} }).then(response => {
|
||||
if (generation !== dashboardGeneration) return;
|
||||
// Compatibility with servers that have not gained the summary API.
|
||||
if (!Array.isArray(response.data?.items)) { legacyDashboard = true; return loadLegacy(); }
|
||||
state.items = (append ? state.items : []).concat(response.data.items.map(decorateSummary));
|
||||
state.dashboardCursor = response.data.cursor;
|
||||
state.dashboardTotals = response.data;
|
||||
}, error => {
|
||||
if (generation !== dashboardGeneration) return;
|
||||
if (error.status === 404) { legacyDashboard = true; return loadLegacy(); }
|
||||
state.dashboardError = "Projects could not be loaded. Please try again.";
|
||||
}).finally(() => {
|
||||
if (generation === dashboardGeneration) { state.loading = false; state.loadingMore = false; }
|
||||
});
|
||||
}
|
||||
state.loadMoreProjects = () => loadAll(true);
|
||||
let reloadTimer;
|
||||
state.watchGroup(["search", "typeFilter", "orderBy", "projectView"], () => {
|
||||
if (legacyDashboard) return;
|
||||
if (reloadTimer) timers.timeout.cancel(reloadTimer);
|
||||
reloadTimer = timers.timeout(() => loadAll(), 150);
|
||||
}, false);
|
||||
state.watch("filters", () => {
|
||||
if (!legacyDashboard) loadAll();
|
||||
}, true, false);
|
||||
state.on("dispose", () => { dashboardGeneration++; });
|
||||
loadAll();
|
||||
|
||||
// Whole row opens the anonymized view; clicks on links, buttons and the
|
||||
@@ -773,17 +830,32 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
});
|
||||
};
|
||||
|
||||
function waitRepoToBeReady(repoId, callback, onError) {
|
||||
http.get("/api/repo/" + repoId).then((res) => {
|
||||
function waitRepoToBeReady(repoId, callback, onError, previousStatus) {
|
||||
http.get("/api/repo/" + repoId).then(async (res) => {
|
||||
let statusChanged = previousStatus !== undefined && previousStatus !== res.data.status;
|
||||
for (const item of state.items) {
|
||||
if (item._type === "repo" && item.repoId == repoId) {
|
||||
statusChanged = statusChanged || item.status !== res.data.status;
|
||||
const neededAttention = state.needsAttention(item);
|
||||
item.status = res.data.status;
|
||||
item.statusMessage = res.data.statusMessage;
|
||||
item._statusKey = statusKey(item.status);
|
||||
if (item._statusKey !== "progress") item._stale = false;
|
||||
const needsAttention = state.needsAttention(item);
|
||||
if (state.dashboardTotals && neededAttention !== needsAttention) {
|
||||
state.dashboardTotals.attention = Math.max(0, state.dashboardTotals.attention + (needsAttention ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (statusChanged && !legacyDashboard) {
|
||||
state.dashboardCursor = null;
|
||||
const selected = state.selectedProject;
|
||||
await loadAll();
|
||||
if (selected && state.selectedProject === selected) {
|
||||
state.selectedProject = state.items.find(item => item._type === selected._type && item._id === selected._id) || null;
|
||||
}
|
||||
}
|
||||
if (
|
||||
res.data.status == "ready" ||
|
||||
res.data.status == "error" ||
|
||||
@@ -793,7 +865,7 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
callback(res.data);
|
||||
return;
|
||||
}
|
||||
timers.timeout(() => waitRepoToBeReady(repoId, callback, onError), 2500);
|
||||
timers.timeout(() => waitRepoToBeReady(repoId, callback, onError, res.data.status), 2500);
|
||||
}, onError);
|
||||
}
|
||||
|
||||
@@ -819,7 +891,7 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
toast.title = `${item._id} is removed.`;
|
||||
toast.body = `The ${label} ${item._id} is removed.`;
|
||||
|
||||
});
|
||||
}, undefined, item.status);
|
||||
} else {
|
||||
toast.title = `${item._id} is removed.`;
|
||||
toast.body = `The ${label} ${item._id} is removed.`;
|
||||
@@ -860,7 +932,7 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
toast.title = `${item._id} is refreshed.`;
|
||||
toast.body = `The ${label} ${item._id} is refreshed.`;
|
||||
|
||||
}, onError);
|
||||
}, onError, item.status);
|
||||
} else {
|
||||
toast.title = `${item._id} is refreshed.`;
|
||||
toast.body = `The ${label} ${item._id} is refreshed.`;
|
||||
@@ -887,7 +959,7 @@ export const unifiedDashboardController = function (state, http, location, promi
|
||||
toast.title = `${item._id} is extended.`;
|
||||
toast.body = `The expiration of ${label} ${item._id} is extended by 6 months.`;
|
||||
|
||||
});
|
||||
}, undefined, item.status);
|
||||
} else {
|
||||
toast.title = `${item._id} is extended.`;
|
||||
toast.body = `The expiration of ${label} ${item._id} is extended by 6 months.`;
|
||||
@@ -2065,6 +2137,14 @@ export const anonymizeController = function (state, http, html, params, location
|
||||
export const exploreController = function (state, http, location, params, html, promises) {
|
||||
const timers = createTimers();
|
||||
const listen = createListeners();
|
||||
state.on("dark-mode", (event, on) => {
|
||||
if (!state.aceOption) return;
|
||||
if (on) {
|
||||
state.aceOption.theme = "nord_dark";
|
||||
} else {
|
||||
state.aceOption.theme = "chrome";
|
||||
}
|
||||
});
|
||||
let contentGeneration = 0;
|
||||
let destroyed = false;
|
||||
state.on("dispose", () => {
|
||||
@@ -2618,7 +2698,7 @@ export const exploreController = function (state, http, location, params, html,
|
||||
e.stop();
|
||||
});
|
||||
|
||||
listen(window, "hashchange", () => applyHashFromUrl(false));
|
||||
const removeHashListener = listen(window, "hashchange", () => applyHashFromUrl(false));
|
||||
|
||||
_editor.setFontSize(state.aceOption.fontSize);
|
||||
_editor.setReadOnly(state.aceOption.readOnly);
|
||||
@@ -2649,15 +2729,9 @@ export const exploreController = function (state, http, location, params, html,
|
||||
_editor.session.setTabSize(state.aceOption.tabSize);
|
||||
_editor.setBehavioursEnabled(state.aceOption.enableBehaviours);
|
||||
_editor.setFadeFoldWidgets(state.aceOption.fadeFoldWidgets);
|
||||
return removeHashListener;
|
||||
},
|
||||
};
|
||||
state.on("dark-mode", (event, on) => {
|
||||
if (on) {
|
||||
state.aceOption.theme = "nord_dark";
|
||||
} else {
|
||||
state.aceOption.theme = "chrome";
|
||||
}
|
||||
});
|
||||
if (state.isDarkMode) {
|
||||
state.aceOption.theme = "nord_dark";
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user