From 45abf5cb3a1e93e98e66e26006a2f25ef8fa4dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Sundal=20Asp=C3=A5s?= Date: Tue, 25 Feb 2025 11:18:03 +0100 Subject: [PATCH 1/3] fix cache key issue --- dash/_callback.py | 1 + dash/long_callback/managers/__init__.py | 4 ++-- dash/long_callback/managers/celery_manager.py | 2 +- dash/long_callback/managers/diskcache_manager.py | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dash/_callback.py b/dash/_callback.py index 071c209dec..5460094b30 100644 --- a/dash/_callback.py +++ b/dash/_callback.py @@ -398,6 +398,7 @@ def add_context(*args, **kwargs): # Inputs provided as dict is kwargs. func_args if func_args else func_kwargs, long.get("cache_args_to_ignore", []), + callback_ctx.get("triggered_inputs", []), ) if old_job: diff --git a/dash/long_callback/managers/__init__.py b/dash/long_callback/managers/__init__.py index 5bfdc837bc..612f57c673 100644 --- a/dash/long_callback/managers/__init__.py +++ b/dash/long_callback/managers/__init__.py @@ -54,7 +54,7 @@ def get_result(self, key, job): def get_updated_props(self, key): raise NotImplementedError - def build_cache_key(self, fn, args, cache_args_to_ignore): + def build_cache_key(self, fn, args, cache_args_to_ignore, triggered): fn_source = inspect.getsource(fn) if not isinstance(cache_args_to_ignore, (list, tuple)): @@ -68,7 +68,7 @@ def build_cache_key(self, fn, args, cache_args_to_ignore): arg for i, arg in enumerate(args) if i not in cache_args_to_ignore ] - hash_dict = dict(args=args, fn_source=fn_source) + hash_dict = dict(args=args, fn_source=fn_source, triggered=triggered) if self.cache_by is not None: # Caching enabled diff --git a/dash/long_callback/managers/celery_manager.py b/dash/long_callback/managers/celery_manager.py index 612cc245fb..53b3684235 100644 --- a/dash/long_callback/managers/celery_manager.py +++ b/dash/long_callback/managers/celery_manager.py @@ -26,7 +26,7 @@ def __init__(self, celery_app, cache_by=None, expire=None): :param cache_by: A list of zero-argument functions. When provided, caching is enabled and the return values of these functions are combined with the callback - function's input arguments and source code to generate cache keys. + function's input arguments, triggered inputs and source code to generate cache keys. :param expire: If provided, a cache entry will be removed when it has not been accessed for ``expire`` seconds. If not provided, the lifetime of cache entries diff --git a/dash/long_callback/managers/diskcache_manager.py b/dash/long_callback/managers/diskcache_manager.py index e1a110f14f..bc1ad3fdbc 100644 --- a/dash/long_callback/managers/diskcache_manager.py +++ b/dash/long_callback/managers/diskcache_manager.py @@ -25,7 +25,7 @@ def __init__(self, cache=None, cache_by=None, expire=None): :param cache_by: A list of zero-argument functions. When provided, caching is enabled and the return values of these functions are combined with the callback - function's input arguments and source code to generate cache keys. + function's input arguments, triggered inputs and source code to generate cache keys. :param expire: If provided, a cache entry will be removed when it has not been accessed for ``expire`` seconds. If not provided, the lifetime of cache entries From 8e73ed1d632c930230e714d8802470bcd066ca81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Sundal=20Asp=C3=A5s?= Date: Tue, 25 Feb 2025 11:49:21 +0100 Subject: [PATCH 2/3] Add cache_ignore_triggered as optional param in callback --- dash/_callback.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dash/_callback.py b/dash/_callback.py index 5460094b30..1366bbd366 100644 --- a/dash/_callback.py +++ b/dash/_callback.py @@ -70,6 +70,7 @@ def callback( cancel=None, manager=None, cache_args_to_ignore=None, + cache_ignore_triggered=True, on_error: Optional[Callable[[Exception], Any]] = None, **_kwargs, ): @@ -139,6 +140,9 @@ def callback( with keyword arguments (Input/State provided in a dict), this should be a list of argument names as strings. Otherwise, this should be a list of argument indices as integers. + :param cache_ignore_triggered: + Whether to ignore which inputs triggered the callback when creating + the cache. :param interval: Time to wait between the long callback update requests. :param on_error: @@ -185,6 +189,8 @@ def callback( if cache_args_to_ignore: long_spec["cache_args_to_ignore"] = cache_args_to_ignore + long_spec["cache_ignore_triggered"] = cache_ignore_triggered + return register_callback( callback_list, callback_map, @@ -393,12 +399,16 @@ def add_context(*args, **kwargs): job_id = flask.request.args.get("job") old_job = flask.request.args.getlist("oldJob") + cache_ignore_triggered = long.get("cache_ignore_triggered", True) + current_key = callback_manager.build_cache_key( func, # Inputs provided as dict is kwargs. func_args if func_args else func_kwargs, long.get("cache_args_to_ignore", []), - callback_ctx.get("triggered_inputs", []), + None + if cache_ignore_triggered + else callback_ctx.get("triggered_inputs", []), ) if old_job: From 8920101c8f5351dc2182e95a70e2d322a9bcceb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Sundal=20Asp=C3=A5s?= Date: Tue, 25 Feb 2025 12:12:21 +0100 Subject: [PATCH 3/3] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e1bd29118..3e2f6776d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#3080](https://github.com/plotly/dash/pull/3080) Fix docstring generation for components using single-line or nonstandard-indent leading comments - [#3103](https://github.com/plotly/dash/pull/3103) Fix Graph component becomes unresponsive if an invalid figure is passed +- [#3190](https://github.com/plotly/dash/pull/3190) Fix issue with cache key generation by adding option to include triggered inputs. Fixes [#3189](https://github.com/plotly/dash/issues/3189) ## [2.18.2] - 2024-11-04