项目概述
本项目实现带定向规则的功能开关服务:按用户确定性百分比放量,支持显式允许与拒绝名单,并允许运营者即时关闭任意开关。开关是已部署代码的通行证,唯一安全的形式是能在数秒内关闭。
架构与关键决策
开关是带类型的配置:键、状态、放量百分比与可选名单。评估把稳定用户键哈希进 0–99 的桶与放量比较,桶由用户键推导而不存储,因此放量可复现且单调,提高百分比只会加入用户而非移动用户。缓存按版本从库刷新,评估只读缓存,使请求路径不阻塞于数据库;关闭开关是一等状态并短路一切,且需在库降级时仍可用。
实施与测试
断言分桶在重复调用与模拟重启后稳定;大量用户下断言放量收敛到配置份额;断言关闭开关覆盖名单与百分比、拒绝名单优先于允许名单;断言库不可达时仍能由最后可用缓存服务。
限制与后续
- 每个开关仅一个百分比,无多变量实验框架。
- 仅按用户键评估,按属性定向需规则 DSL。
- 无开关过期,退役为手动清理。
代码示例
pnpm init
pnpm add pg express
pnpm add -D typescript tsx vitest
feature-flag-service/
├── src/evaluate.ts
├── src/bucketing.ts
├── src/rules.ts
├── src/cache.ts
├── tests/evaluate.test.ts
└── package.json
type Flag = { key: string; type: 'boolean'|'string'; default: unknown; rollout: number; rules: Rule[] };
function bucket(flagKey, userKey) {
const h = createHash('sha1').update(flagKey + ':' + userKey).digest();
return h.readUInt32BE(0) % 100;
}
for (const rule of flag.rules) if (matches(rule, ctx)) return rule.value;
if (cache.version !== currentVersion) await refresh();
if (flag.killed) return flag.default;
pnpm vitest run