From b49d5124043b190df42f47e048db93a0075ef361 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 14 Jan 2025 14:06:21 +0530 Subject: [PATCH] feat: cache documents in client cache No need to query 1 key at a time. --- .../core/doctype/system_settings/system_settings.py | 5 +---- frappe/locale.py | 2 +- frappe/tests/test_client_cache.py | 5 +++++ frappe/utils/redis_wrapper.py | 11 +++++++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py index 82c55ad518..1886f23391 100644 --- a/frappe/core/doctype/system_settings/system_settings.py +++ b/frappe/core/doctype/system_settings/system_settings.py @@ -227,10 +227,7 @@ def get_system_settings(key: str): """Return the value associated with the given `key` from System Settings DocType.""" if not (system_settings := getattr(frappe.local, "system_settings", None)): try: - system_settings = frappe.client_cache.get_value(cache_key) - if not system_settings: - system_settings = frappe.get_cached_doc("System Settings") - frappe.client_cache.set_value(cache_key, system_settings) + system_settings = frappe.client_cache.get_doc("System Settings") frappe.local.system_settings = system_settings except frappe.DoesNotExistError: # possible during new install frappe.clear_last_message() diff --git a/frappe/locale.py b/frappe/locale.py index 9e4c027531..cca885087a 100644 --- a/frappe/locale.py +++ b/frappe/locale.py @@ -47,6 +47,6 @@ def get_locale_value(key: str, language: str | None = None) -> str | None: """ lang = language or frappe.local.lang if lang: - value = frappe.db.get_value("Language", lang, key) + value = frappe.client_cache.get_doc("Language", lang).get(key) return value or frappe.db.get_default(key) diff --git a/frappe/tests/test_client_cache.py b/frappe/tests/test_client_cache.py index f9818b2a72..c65d4960ac 100644 --- a/frappe/tests/test_client_cache.py +++ b/frappe/tests/test_client_cache.py @@ -111,3 +111,8 @@ class TestClientCache(IntegrationTestCase): with self.assertRedisCallCounts(0): self.assertEqual(frappe.client_cache.get_value(TEST_KEY, generator=lambda: val), val) + + def test_get_doc(self): + frappe.client_cache.get_doc("User", "Guest") + with self.assertRedisCallCounts(0): + frappe.client_cache.get_doc("User", "Guest") diff --git a/frappe/utils/redis_wrapper.py b/frappe/utils/redis_wrapper.py index e6b37b288f..ace4276fdd 100644 --- a/frappe/utils/redis_wrapper.py +++ b/frappe/utils/redis_wrapper.py @@ -531,6 +531,17 @@ class ClientCache: # doesn't send invalidation. _ = self.redis.get_value(key, shared=True, use_local_cache=not self.healthy) + def get_doc(self, doctype: str, name: str | None = None): + """Utility to fetch and store documents in client cache. + + Use sparingly, this should ideally be used for settings and doctypes that have few known + number of documents. + """ + if not name: + name = doctype # singles + key = frappe.get_document_cache_key(doctype, name) + return self.get_value(key, generator=lambda: frappe.get_doc(doctype, name)) + def ensure_max_size(self): if len(self.cache) >= self.maxsize: with self.lock, suppress(RuntimeError):