Skip to content

Commit 535db8b

Browse files
fix(masking): add emergency fallback pattern when registry changes rapidly (#15353)
1 parent 28da447 commit 535db8b

File tree

1 file changed

+28
-6
lines changed

1 file changed

+28
-6
lines changed

metadata-ingestion/src/datahub/masking/masking_filter.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ def _check_and_rebuild_pattern(self) -> None:
6767
"""Check if pattern needs rebuilding and rebuild if necessary."""
6868
MAX_REBUILD_ATTEMPTS = 10 # Prevent infinite loops
6969

70+
# Track last successfully built pattern for emergency fallback
71+
last_built_pattern: Optional[re.Pattern] = None
72+
last_built_replacements: Dict[str, str] = {}
73+
last_built_version: int = 0
74+
7075
for attempt in range(MAX_REBUILD_ATTEMPTS):
7176
# Quick check WITHOUT lock (fast path)
7277
current_version = self._registry.get_version()
@@ -100,6 +105,11 @@ def _check_and_rebuild_pattern(self) -> None:
100105
try:
101106
new_pattern = re.compile(pattern_str)
102107
new_replacements = {value: name for value, name in sorted_secrets}
108+
109+
# Save this for emergency fallback
110+
last_built_pattern = new_pattern
111+
last_built_replacements = new_replacements
112+
last_built_version = current_version
103113
except Exception as e:
104114
logger.error(f"Failed to compile masking pattern: {e}")
105115
return # Keep using old pattern
@@ -150,12 +160,24 @@ def _check_and_rebuild_pattern(self) -> None:
150160
# Continue to next iteration of the loop
151161

152162
# If we get here, we failed after MAX_REBUILD_ATTEMPTS
153-
logger.error(
154-
f"CRITICAL: Failed to rebuild masking pattern after {MAX_REBUILD_ATTEMPTS} attempts. "
155-
f"Secrets are being modified too rapidly. "
156-
f"Continuing with potentially stale pattern (version {self._last_version}). "
157-
f"Some newly added secrets may not be masked until rate of changes decreases."
158-
)
163+
# Emergency fallback: Use the last pattern we built if we have no pattern at all
164+
# Better to have a slightly stale pattern than no masking at all
165+
with self._pattern_lock:
166+
if self._pattern is None and last_built_pattern is not None:
167+
self._pattern = last_built_pattern
168+
self._replacements = last_built_replacements
169+
self._last_version = last_built_version
170+
logger.warning(
171+
f"Emergency fallback: Using potentially stale pattern (version {last_built_version}) "
172+
f"because no pattern was previously available and registry is changing too rapidly."
173+
)
174+
else:
175+
logger.error(
176+
f"CRITICAL: Failed to rebuild masking pattern after {MAX_REBUILD_ATTEMPTS} attempts. "
177+
f"Secrets are being modified too rapidly. "
178+
f"Continuing with potentially stale pattern (version {self._last_version}). "
179+
f"Some newly added secrets may not be masked until rate of changes decreases."
180+
)
159181
# Keep using the old pattern rather than crashing - graceful degradation
160182

161183
def mask_text(self, text: str) -> str:

0 commit comments

Comments
 (0)