From 4dc5c012daeff93c738daa7921cbda1832a63384 Mon Sep 17 00:00:00 2001 From: Jeremie Pardou <jeremie@baserow.io> Date: Mon, 24 Mar 2025 09:44:55 +0100 Subject: [PATCH] Fix schema cache issue --- backend/src/baserow/contrib/database/table/cache.py | 7 ++++++- backend/src/baserow/contrib/database/table/signals.py | 1 + .../contrib/integrations/local_baserow/receivers.py | 11 +++++++++++ .../integrations/local_baserow/service_types.py | 2 +- backend/src/baserow/contrib/integrations/signals.py | 5 ++--- backend/src/baserow/core/cache.py | 3 ++- ...invalidation_on_field_change_for_data_sources.json | 8 ++++++++ 7 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 backend/src/baserow/contrib/integrations/local_baserow/receivers.py create mode 100644 changelog/entries/unreleased/bug/fix_cache_invalidation_on_field_change_for_data_sources.json diff --git a/backend/src/baserow/contrib/database/table/cache.py b/backend/src/baserow/contrib/database/table/cache.py index 61b0db07b..762761d49 100644 --- a/backend/src/baserow/contrib/database/table/cache.py +++ b/backend/src/baserow/contrib/database/table/cache.py @@ -67,11 +67,16 @@ def clear_generated_model_cache(): def invalidate_table_in_model_cache(table_id: int): + from baserow.contrib.database.table.models import Table + from baserow.contrib.database.table.signals import table_schema_changed + + # Send signal for other potential cached values + table_schema_changed.send(Table, table_id=table_id) + if settings.BASEROW_DISABLE_MODEL_CACHE: return None new_version = str(uuid.uuid4()) # Make sure to invalidate ourselves and any directly connected tables. - from baserow.contrib.database.table.models import Table Table.objects_and_trash.filter(id=table_id).update(version=new_version) diff --git a/backend/src/baserow/contrib/database/table/signals.py b/backend/src/baserow/contrib/database/table/signals.py index f5dfa690e..7ff819c3a 100644 --- a/backend/src/baserow/contrib/database/table/signals.py +++ b/backend/src/baserow/contrib/database/table/signals.py @@ -8,6 +8,7 @@ table_created = Signal() table_updated = Signal() table_deleted = Signal() tables_reordered = Signal() +table_schema_changed = Signal() @receiver(post_delete, sender=Table) diff --git a/backend/src/baserow/contrib/integrations/local_baserow/receivers.py b/backend/src/baserow/contrib/integrations/local_baserow/receivers.py new file mode 100644 index 000000000..5ec278f93 --- /dev/null +++ b/backend/src/baserow/contrib/integrations/local_baserow/receivers.py @@ -0,0 +1,11 @@ +from django.dispatch import receiver + +from baserow.contrib.database.table.signals import table_schema_changed +from baserow.core.cache import global_cache, local_cache + + +@receiver(table_schema_changed) +def invalidate_table_cache(sender, table_id, **kwargs): + # Invalidate local cache when the table schema is updated + global_cache.invalidate(f"table_{table_id}__service_schema") + local_cache.delete(f"integration_service_{table_id}_table_model") diff --git a/backend/src/baserow/contrib/integrations/local_baserow/service_types.py b/backend/src/baserow/contrib/integrations/local_baserow/service_types.py index c223e3855..6ad29d144 100644 --- a/backend/src/baserow/contrib/integrations/local_baserow/service_types.py +++ b/backend/src/baserow/contrib/integrations/local_baserow/service_types.py @@ -495,7 +495,7 @@ class LocalBaserowTableServiceType(LocalBaserowServiceType): return None properties = global_cache.get( - f"table_{service.table_id}_{service.table.version}__service_schema", + f"table_{service.table_id}__service_schema", default=lambda: self._get_table_properties(service, allowed_fields), timeout=SCHEMA_CACHE_TTL, ) diff --git a/backend/src/baserow/contrib/integrations/signals.py b/backend/src/baserow/contrib/integrations/signals.py index da6c8c9ef..0180c90cc 100644 --- a/backend/src/baserow/contrib/integrations/signals.py +++ b/backend/src/baserow/contrib/integrations/signals.py @@ -1,7 +1,6 @@ +from baserow.contrib.integrations.local_baserow.receivers import invalidate_table_cache from baserow.contrib.integrations.local_baserow.signals import ( handle_local_baserow_field_updated_changes, ) -__all__ = [ - "handle_local_baserow_field_updated_changes", -] +__all__ = ["handle_local_baserow_field_updated_changes", "invalidate_table_cache"] diff --git a/backend/src/baserow/core/cache.py b/backend/src/baserow/core/cache.py index a679c4625..849c1cd86 100644 --- a/backend/src/baserow/core/cache.py +++ b/backend/src/baserow/core/cache.py @@ -65,7 +65,8 @@ class LocalCache: ): del self._local.cache[k] else: - del self._local.cache[key] + if key in self._local.cache: + del self._local.cache[key] def clear(self): """ diff --git a/changelog/entries/unreleased/bug/fix_cache_invalidation_on_field_change_for_data_sources.json b/changelog/entries/unreleased/bug/fix_cache_invalidation_on_field_change_for_data_sources.json new file mode 100644 index 000000000..d9fe5d942 --- /dev/null +++ b/changelog/entries/unreleased/bug/fix_cache_invalidation_on_field_change_for_data_sources.json @@ -0,0 +1,8 @@ +{ + "type": "bug", + "message": "Fix cache invalidation on field change for data sources", + "domain": "builder", + "issue_number": null, + "bullet_points": [], + "created_at": "2025-03-24" +} \ No newline at end of file