From c98fff79c2e1f3801713e2f47b16cb87b86f7b52 Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Thu, 30 Apr 2026 17:21:51 +0000 Subject: [PATCH] perf(cron): memoize ensure_cron_project() per get_cli_sessions() scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-release Opus review on PR #1345 (Finding #3) flagged that get_cli_sessions() was calling ensure_cron_project() once per cron session in the loop — N lock acquires + N disk reads of projects.json for N cron sessions per sidebar refresh. Hoist a per-scan lazy memoizer (_cron_pid()) so we pay the resolution cost at most once per get_cli_sessions() call. The memoizer is local to the function (closure) so it's naturally scoped to a single scan and doesn't leak across calls. Could also have made ensure_cron_project() module-memoized, but that would need invalidation on project deletion — the per-scan cache is simpler and correct without coordination. --- api/models.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api/models.py b/api/models.py index b4216fad..941f988e 100644 --- a/api/models.py +++ b/api/models.py @@ -953,6 +953,15 @@ def get_cli_sessions() -> list: except ImportError: _cli_profile = None # older agent -- fall back to no profile + # Memoize the cron project ID for this scan so we don't pay a lock-acquire + + # disk-read of projects.json per cron session in the loop below. + # Resolved lazily on the first cron session we encounter. + _cron_pid_cache = [None] # list-as-cell so the closure can mutate + def _cron_pid(): + if _cron_pid_cache[0] is None: + _cron_pid_cache[0] = ensure_cron_project() + return _cron_pid_cache[0] + try: for row in read_importable_agent_session_rows(db_path, limit=200, log=logger, exclude_sources=None): sid = row['id'] @@ -991,7 +1000,7 @@ def get_cli_sessions() -> list: 'updated_at': raw_ts, 'pinned': False, 'archived': False, - 'project_id': ensure_cron_project() if is_cron_session(sid, _source) else None, + 'project_id': _cron_pid() if is_cron_session(sid, _source) else None, 'profile': profile, 'source_tag': _source, 'raw_source': row.get('raw_source'),