-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[AI-6101] Add support for customizable cache keys for persistent cache #21316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b3487a9
Add support for customizable cache keys to store log cursor
AAraKKe b270356
Add changelog
AAraKKe d68445f
Remove PersistentCacheKey lefotver from AgentCheck
AAraKKe 80ab48b
Fix docstring mistakes
AAraKKe 4c4ed30
Reduce cache key scope to checks with the same name
AAraKKe f59d322
Add test to cover restart behavior
AAraKKe 5dea5c4
Address most of the comments on the PR
AAraKKe b055b39
Fix imports in tests
AAraKKe 9cadb23
Replace manual sorthing by mutable_hash utility
AAraKKe 79922bc
Update changelog message
AAraKKe 69c0fbf
Remove CacheKeyManager
AAraKKe fb3b214
Reword docstrings
AAraKKe 8b2775a
Finalize update of ConfigSet
AAraKKe 5956587
Reframe implementation towards a invalidation strategy more than the …
AAraKKe 26d9262
Fix module renaming and keep tests dry
AAraKKe 1ac9e1b
Fix typo in prefix method
AAraKKe b856a01
Simplify implementation to use persistent_cache_id
AAraKKe 91604c3
Simplify id namespace calculation
AAraKKe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add support for customizable cache keys to manage logs cursor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
datadog_checks_base/datadog_checks/base/utils/cache_key/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# (C) Datadog, Inc. 2025-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from .base import CacheKey | ||
from .full_config import FullConfigCacheKey | ||
from .config_set import ConfigSetCacheKey | ||
from .manager import CacheKeyManager, CacheKeyType | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
__all__ = ["CacheKey", "FullConfigCacheKey", "ConfigSetCacheKey", "CacheKeyManager", "CacheKeyType"] |
34 changes: 34 additions & 0 deletions
34
datadog_checks_base/datadog_checks/base/utils/cache_key/base.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# (C) Datadog, Inc. 2025-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from __future__ import annotations | ||
|
||
from abc import ABC, abstractmethod | ||
from typing import TYPE_CHECKING | ||
|
||
if TYPE_CHECKING: | ||
from datadog_checks.base import AgentCheck | ||
|
||
|
||
class CacheKey(ABC): | ||
def __init__(self, check: AgentCheck): | ||
"""Abstract base class for cache keys management. | ||
|
||
Any implementation of this class provides the logic to generate cache keys to be used in the Agent persistent | ||
cache. | ||
""" | ||
self.check = check | ||
|
||
@abstractmethod | ||
def base_key(self) -> str: | ||
""" | ||
Abstract method that derives the cache key for the particular implementation. | ||
This method must return a stable key that only differs between instances based on the | ||
specific implmentation of the invalidation logic. | ||
""" | ||
|
||
def key_for(self, context: str) -> str: | ||
""" | ||
Returns a key that is a combination of the base key and the provided context. | ||
""" | ||
return f"{self.base_key()}_{context}" |
54 changes: 54 additions & 0 deletions
54
datadog_checks_base/datadog_checks/base/utils/cache_key/config_set.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# (C) Datadog, Inc. 2025-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from __future__ import annotations | ||
|
||
from collections.abc import Collection | ||
from typing import TYPE_CHECKING | ||
|
||
from .base import CacheKey | ||
|
||
if TYPE_CHECKING: | ||
from typing import Any, Iterable | ||
|
||
from datadog_checks.base import AgentCheck | ||
|
||
|
||
class ConfigSetCacheKey(CacheKey): | ||
""" | ||
Cache key that is derived from a subset of the check's config options. | ||
When the subset of config options changes, the cache is invalidated. | ||
""" | ||
|
||
def __init__( | ||
self, | ||
check: AgentCheck, | ||
config_options: Collection[str], | ||
): | ||
super().__init__(check) | ||
self.config_options = set(config_options) | ||
# Config cannot change on the fly, so we can cache the key | ||
self.__key: str | None = None | ||
|
||
def base_key(self) -> str: | ||
if self.__key is not None: | ||
return self.__key | ||
|
||
merged_config = self.check.init_config | self.check.instance | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
selected_values = tuple(values for key, values in merged_config.items() if key in self.config_options) | ||
self.__key = str(hash(self.__sorted_values(selected_values))) | ||
return self.__key | ||
|
||
def __sorted_values(self, values: Iterable[Any]) -> tuple[str, ...]: | ||
sorted_values = [] | ||
|
||
for value in values: | ||
if isinstance(value, (list, tuple, set, frozenset)): | ||
sorted_values.extend(self.__sorted_values(value)) | ||
elif isinstance(value, dict): | ||
for key, dict_value in value.items(): | ||
sorted_values.append(f"{key}:{self.__sorted_values(dict_value)}") | ||
else: | ||
sorted_values.append(str(value)) | ||
return tuple(sorted(sorted_values)) | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
19 changes: 19 additions & 0 deletions
19
datadog_checks_base/datadog_checks/base/utils/cache_key/full_config.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# (C) Datadog, Inc. 2025-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from __future__ import annotations | ||
|
||
from .base import CacheKey | ||
|
||
|
||
class FullConfigCacheKey(CacheKey): | ||
""" | ||
Cache key based on the check_id of the check where it is being used. | ||
|
||
The check_id includes a digest of the full configuration of the check. The cache is invalidated | ||
whenever the configuration of the check changes. | ||
""" | ||
|
||
def base_key(self) -> str: | ||
# The check_id is injected by the agent containing the config digest | ||
return str(self.check.check_id) | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
76 changes: 76 additions & 0 deletions
76
datadog_checks_base/datadog_checks/base/utils/cache_key/manager.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# (C) Datadog, Inc. 2025-present | ||
# All rights reserved | ||
# Licensed under a 3-clause BSD style license (see LICENSE) | ||
from __future__ import annotations | ||
|
||
from enum import Enum, auto | ||
from typing import TYPE_CHECKING | ||
|
||
if TYPE_CHECKING: | ||
from collections.abc import Callable | ||
|
||
from datadog_checks.base import AgentCheck | ||
|
||
from .base import CacheKey | ||
from .full_config import FullConfigCacheKey | ||
|
||
|
||
class CacheKeyType(Enum): | ||
"""Enum used to identify the type of cache key.""" | ||
|
||
LOG_CURSOR = auto() | ||
|
||
|
||
class CacheKeyManager: | ||
def __init__(self, check: AgentCheck): | ||
""" | ||
Manager of cache keys for the persistent cache. | ||
This class defined the different kinds of persistent cache keys to be used when adding and retrieving | ||
from the agent persistent cache. The AentCheck can use this manager to to ensure that the correct cache key is | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
used in each consistently through the different check invocations. | ||
""" | ||
self.keys: dict[CacheKeyType, CacheKey] = {} | ||
self.check = check | ||
self.default_cache_key = FullConfigCacheKey(self.check) | ||
|
||
def __retrieve_cache_key( | ||
self, | ||
key_type: CacheKeyType, | ||
default_factory: Callable[[], CacheKey] | None = None, | ||
) -> CacheKey: | ||
if (key := self.keys.get(key_type)) is not None: | ||
return key | ||
|
||
if default_factory is None: | ||
self.check.log.warning( | ||
"{key_type} cache key requested wihtout a default factory supplied. " | ||
"Using default full config cache key.", | ||
extra={"key_type": key_type.name}, | ||
) | ||
AAraKKe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
self.keys[key_type] = default_factory() if default_factory is not None else self.default_cache_key | ||
return self.keys[key_type] | ||
|
||
def has_cache_key(self, key_type: CacheKeyType) -> bool: | ||
return key_type in self.keys | ||
|
||
def get(self, *, cache_key_type: CacheKeyType, default_factory: Callable[[], CacheKey] | None = None) -> CacheKey: | ||
""" | ||
Returns the cache key for the given cache key type. | ||
""" | ||
return self.__retrieve_cache_key( | ||
key_type=cache_key_type, | ||
default_factory=default_factory, | ||
) | ||
|
||
def add(self, *, cache_key_type: CacheKeyType, key_factory: Callable[[], CacheKey], override: bool = False): | ||
""" | ||
Adds the cache key for the given cache key type. | ||
The provided cache key is only added if the cache key type is not already in the manager. To force the addition | ||
of the cache key, set the `override` argument to `True`. | ||
""" | ||
if cache_key_type in self.keys and not override: | ||
return | ||
self.keys[cache_key_type] = key_factory() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.