From 6613ed76fe6a70f33db2b4419c2cb82f1e49461c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 21 Mar 2024 16:48:29 +0530 Subject: [PATCH] fix: ensure that prepared report is set even on timeout (#25565) * fix: ensure that prepared report is set even on timeout Under following condition prepared report is never enabled: - Process takes too much time and is killed - HTTP timeout Fix: - We spawn a thread and ask it to wait till prepared report threshold time is elapsed and set prepared report on it. - Condvar is used to immdiately wake up and end the thread if report finsihed early. * refactor: use threading.Timer No need to implement it ourselves --- frappe/core/doctype/report/report.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index c108c8ee6e..ed42a61747 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -2,6 +2,7 @@ # License: MIT. See LICENSE import datetime import json +import threading import frappe import frappe.desk.query_report @@ -15,6 +16,8 @@ from frappe.modules.export_file import export_to_files from frappe.utils import cint, cstr from frappe.utils.safe_exec import check_safe_sql_query, safe_exec +PREPARED_REPORT_THRESHOLD = 20 # seconds + class Report(Document): # begin: auto-generated types @@ -153,21 +156,24 @@ class Report(Document): def execute_script_report(self, filters): # save the timestamp to automatically set to prepared - threshold = 15 - start_time = datetime.datetime.now() + if not self.prepared_report: + set_prepared_report = threading.Timer( + interval=PREPARED_REPORT_THRESHOLD, + function=enable_prepared_report, + kwargs={"report": self.name, "site": frappe.local.site}, + ) + set_prepared_report.start() + # The JOB if self.is_standard == "Yes": res = self.execute_module(filters) else: res = self.execute_script(filters) - # automatically set as prepared + set_prepared_report.cancel() execution_time = (datetime.datetime.now() - start_time).total_seconds() - if execution_time > threshold and not self.prepared_report: - frappe.enqueue(enable_prepared_report, report=self.name) - frappe.cache.hset("report_execution_time", self.name, execution_time) return res @@ -414,5 +420,9 @@ def get_group_by_column_label(args, meta): return label -def enable_prepared_report(report: str): - frappe.db.set_value("Report", report, "prepared_report", 1) +def enable_prepared_report(*, site: str, report: str): + frappe.init(site) + frappe.connect() + frappe.db.set_value("Report", report, "prepared_report", 1, update_modified=True) + frappe.db.commit() + frappe.destroy()