63 lines
1.7 KiB
Python
63 lines
1.7 KiB
Python
|
|
"""生成链路的显式灰度开关。"""
|
||
|
|
import os
|
||
|
|
import hashlib
|
||
|
|
|
||
|
|
|
||
|
|
DEFAULTS = {
|
||
|
|
"DOCUMENT_IR_V1": True,
|
||
|
|
"PLAN_SNAPSHOT_V1": True,
|
||
|
|
"SCENARIO_ENGINE_V2": False,
|
||
|
|
"OUTPUT_RECONCILIATION_V1": True,
|
||
|
|
"RETENTION_CLEANUP_V1": False,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def enabled(name: str) -> bool:
|
||
|
|
if name not in DEFAULTS:
|
||
|
|
raise KeyError(f"unknown feature flag: {name}")
|
||
|
|
value = os.getenv(f"INSURANCE_{name}")
|
||
|
|
if value is None:
|
||
|
|
return DEFAULTS[name]
|
||
|
|
return value.strip().lower() in {"1", "true", "yes", "on"}
|
||
|
|
|
||
|
|
|
||
|
|
def public_flags() -> dict[str, bool]:
|
||
|
|
return {name: enabled(name) for name in DEFAULTS}
|
||
|
|
|
||
|
|
|
||
|
|
def enabled_for(name: str, *, identity: str = "", profile: str = "") -> bool:
|
||
|
|
"""支持按 profile 白名单和稳定百分比分桶的灰度判断。"""
|
||
|
|
if not enabled(name):
|
||
|
|
return False
|
||
|
|
profiles = {
|
||
|
|
item.strip() for item in os.getenv(f"INSURANCE_{name}_PROFILES", "").split(",")
|
||
|
|
if item.strip()
|
||
|
|
}
|
||
|
|
if profiles and profile not in profiles:
|
||
|
|
return False
|
||
|
|
percentage = _percentage(name)
|
||
|
|
if percentage >= 100:
|
||
|
|
return True
|
||
|
|
if percentage <= 0 or not identity:
|
||
|
|
return False
|
||
|
|
bucket = int(hashlib.sha256(f"{name}:{identity}".encode("utf-8")).hexdigest()[:8], 16) % 100
|
||
|
|
return bucket < percentage
|
||
|
|
|
||
|
|
|
||
|
|
def rollout_config() -> dict:
|
||
|
|
return {
|
||
|
|
name: {
|
||
|
|
"enabled": enabled(name),
|
||
|
|
"percentage": _percentage(name),
|
||
|
|
"profiles": [item for item in os.getenv(f"INSURANCE_{name}_PROFILES", "").split(",") if item],
|
||
|
|
}
|
||
|
|
for name in DEFAULTS
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def _percentage(name: str) -> int:
|
||
|
|
try:
|
||
|
|
return max(0, min(100, int(os.getenv(f"INSURANCE_{name}_PERCENT", "100"))))
|
||
|
|
except ValueError:
|
||
|
|
return 0
|