JSON 配置变了,就一定要报警吗?先把比较范围写清楚
两份 JSON 字符串不同,业务配置未必不同。对象的键换了顺序、增加了缩进,都可能改变字符串;相反,只盯着几个熟悉的字段,又可能漏掉真正重要的变化。
比对之前,先回答一个问题:这次检查究竟要保护什么?
下面用一个虚构的任务调度配置做例子。它包含三个字段:region 表示运行地区,max_jobs 表示最大并发数,blocked_services 表示禁止使用的服务。当前只关心 search 和 report 两项服务。
假定规则已经明确:地区和并发数必须一致;黑名单中与当前目标无关的服务可以忽略;黑名单是集合,排列顺序和重复项不改变含义。这个约定只适用于本例,不能拿来处理有先后顺序的执行步骤。
一、先看三个容易混淆的变化
旧配置:
{"region":"demo-east","max_jobs":3,"blocked_services":["search","archive"]}
新配置甲:
{"blocked_services":["archive","search","mail"],"max_jobs":3,"region":"demo-east"}
甲只增加了无关的 mail,并调整了字段和数组的排列。针对 search、report 这两项服务,它没有改变本次检查关心的行为。
新配置乙把 blocked_services 改为 [“search”, “report”]。这次必须报变化,因为 report 从允许使用变成了禁止使用。
新配置丙保留旧黑名单,却把 max_jobs 从 3 改为 4。它同样必须报变化。过滤无关黑名单,不能顺手把并发限制也忽略了。
二、把约定写进函数
def signature(config, targets):
required = {"region", "max_jobs", "blocked_services"}
if set(config) != required:
raise ValueError("字段缺失或出现未评估的新字段")
region = config["region"]
jobs = config["max_jobs"]
blocked = config["blocked_services"]
if type(region) is not str or not region:
raise ValueError("region 必须是非空字符串")
if type(jobs) is not int or jobs < 1:
raise ValueError("max_jobs 必须是正整数")
if type(blocked) is not list:
raise ValueError("blocked_services 必须是列表")
if any(type(item) is not str for item in blocked):
raise ValueError("黑名单项必须是字符串")
relevant = frozenset(blocked) & frozenset(targets)
return region, jobs, relevant
def equivalent(old, new, targets):
return signature(old, targets) == signature(new, targets)
这里没有直接把两个 JSON 文本送进哈希函数,而是先构造一份明确的比较结果:地区、并发数、与目标有关的黑名单。对照结果不相同,就表示本次约定关心的配置发生了变化。
类型检查也有用。Python 中 True == 1,但这里的并发数要求整数,不能把 JSON 的 true 当成一个并发任务。因此使用 type(jobs) is int,把布尔值排除在外。
遇到未知字段时,这个示例选择报错,让维护者先评估新字段的作用。否则,对方新增了一个会影响行为的字段,本地函数却继续返回“相同”,容易形成静默漏检。报错表示无法完成本次判断,不代表已经证明业务配置发生变化;调用方应分别记录这两种结果。
三、排序和哈希各自能解决什么
Python 的 json.dumps(…, sort_keys=True) 可以让对象键按顺序输出,但不会替你判断数组是不是集合,更不知道哪些服务与当前任务有关。把所有数组统一排序,反而可能破坏路由优先级、工作流步骤等有序配置的含义。
哈希适合回答“这份内容的字节是否变化”。如果需要比较经过业务规则归一化的结果,也可以在规则明确后计算摘要,用于缓存或快速索引。关键是先定义等价关系,再选择实现方式。
原始配置仍然应保留,便于回看无关字段发生过什么变化。判断时只比较约定范围,记录时保留完整证据,两者可以同时做到。
本文全部配置和服务名均为虚构示例。代码针对上述三字段结构;更复杂的嵌套条件,需要单独定义比较规则。
参考:Python 官方文档,json 模块,sort_keys 参数与编码顺序说明。
- 点赞
- 收藏
- 关注作者
评论(0)