perf: Limit get_open_count to 1s for each count query (#32920)

If left unoptimized this wreaks havoc on database servers and has little
real value. If it's valuable people will complaint about "?" and it will
get fixed.

This constriant on runtime should always be present.
This commit is contained in:
Ankush Menat 2025-06-12 21:17:58 +05:30 committed by GitHub
parent 18b032fc04
commit 7345b6b078
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 20 deletions

View file

@ -2,6 +2,7 @@
# License: MIT. See LICENSE
import json
from typing import Literal
from bs4 import BeautifulSoup
@ -251,6 +252,18 @@ def get_open_count(doctype: str, name: str, items=None):
if frappe.flags.in_migrate or frappe.flags.in_install:
return {"count": []}
# None of the count queries should take more than 1s individually
frappe.db.set_execution_timeout(1)
try:
return _get_linked_document_counts(doctype, name, items)
except Exception as e:
if frappe.db.is_statement_timeout(e):
return {"count": []}
raise
def _get_linked_document_counts(doctype: str, name: str, items=None):
doc = frappe.get_lazy_doc(doctype, name)
doc.check_permission()
meta = doc.meta
@ -342,18 +355,16 @@ def get_external_links(doctype, name, links):
return {"doctype": doctype, "count": total_count, "open_count": open_count}
def get_doc_count(doctype, filters):
return len(
frappe.get_all(
doctype,
fields="name",
filters=filters,
limit=100,
distinct=True,
ignore_ifnull=True,
order_by=None,
def get_doc_count(doctype, filters) -> int | Literal["?"]:
try:
docs = frappe.get_all(
doctype, filters=filters, limit=100, distinct=True, ignore_ifnull=True, order_by=None
)
)
return len(docs)
except Exception as e:
if frappe.db.is_statement_timeout(e): # Skip fetching correct count if it's too slow
return "?"
raise
def get_dynamic_link_filters(doctype, links, fieldname):

View file

@ -457,18 +457,14 @@ frappe.ui.form.Dashboard = class FormDashboard {
$.each(count.internal_links_found, function (i, d) {
me.frm.dashboard.set_badge_count_for_internal_link(
d.doctype,
cint(d.open_count),
cint(d.count),
d.open_count,
d.count,
d.names
);
});
$.each(count.external_links_found, function (i, d) {
me.frm.dashboard.set_badge_count_for_external_link(
d.doctype,
cint(d.open_count),
cint(d.count)
);
me.frm.dashboard.set_badge_count_for_external_link(d.doctype, d.open_count, d.count);
});
}
@ -499,14 +495,20 @@ frappe.ui.form.Dashboard = class FormDashboard {
$link
.find(".open-notification")
.removeClass("hidden")
.html(open_count > 99 ? "99+" : open_count);
.html(cint(open_count) > 99 ? "99+" : open_count);
}
if (count) {
$link
.find(".count")
.removeClass("hidden")
.text(count > 99 ? "99+" : count);
.text(cint(count) > 99 ? "99+" : count)
.attr(
"title",
count != "?"
? __("Count of linked documents")
: __("Accurate count can not be fetched, click here to view all documents")
);
}
}