ffclient.boolvariation 用于执行上下文感知的开关评估,需传入 flag key、ffcontext.context 实例和 sdk 默认值,结果由用户标识、规则配置及当前时间共同决定,不参与规则计算的默认值仅在初始化失败等极端情况下生效。

怎么用 ffclient.BoolVariation 判断开关状态?
直接调用 ffclient.BoolVariation 是最常用、也最容易出错的入口。它不是“查配置”,而是“做一次上下文评估”——结果取决于用户标识、规则配置、当前时间(比如定时开关)三者共同作用。
- 必须传入
ffcontext.Context,不能只传字符串 ID;漏掉这步会触发默认值(比如你传false,但实际想 fallback 到true,就永远得不到) - 第一个参数是 flag key,大小写敏感,且必须和 YAML 里定义的完全一致(
test-flag≠testFlag) - 第三个参数是 SDK 默认值(SDK 层 fallback),不是业务兜底逻辑;它只在初始化失败、网络超时、flag 不存在等极端情况下生效,**不参与规则计算**
- 别在循环里反复新建
ffcontext.NewEvaluationContext("uid");复用 context 实例或提前构造好,避免不必要的 map 分配
示例:
userCtx := ffcontext.NewEvaluationContext("user_12345")
userCtx.AddCustom("region", "cn-east")
userCtx.AddCustom("plan", "pro")
enabled, err := ffclient.BoolVariation("payment-v2", userCtx, false)
if err != nil {
// 注意:err 不代表“开关关了”,而是“评估失败”,比如 YAML 格式错、key 找不到、网络断了
log.Warn("failed to evaluate payment-v2", "err", err)
return false // 这里才该做业务兜底
}
return enabled
为什么 fileretriever 加载 YAML 总是报错?
本地文件加载看似最简单,但路径、编码、结构三处最容易卡住。Go 的 os.Open 默认按当前工作目录解析路径,而很多人误以为是二进制所在目录。
-
Path: "flag-config.goff.yaml"是相对路径,启动命令在哪执行,就从哪开始找;建议统一用绝对路径,或用filepath.Abs动态拼接 - YAML 文件必须是 UTF-8 编码(无 BOM),Windows 记事本另存为时容易带 BOM,导致解析器 panic 报
invalid character '\ufeff' - 顶层必须是 map,不能以 list 开头;常见错误是把多个 flag 写成数组形式,而 go-feature-flag 要求每个 flag 是独立 key
- 字段名大小写敏感:
defaultRule不是defaultrule,percentage下面的 key 必须和variations里完全一致
什么时候该切到 Relay Proxy 模式?
单机 ffclient.Init 适合开发和小流量服务;一旦出现以下任一情况,就该上 Relay Proxy:
- 多个 Go 服务共用同一套 flag 配置,每次改 YAML 都得重启所有进程
- 需要给前端 JS 或 iOS App 提供 flag 服务(它们没法直读 S3/YAML)
- 要审计谁在什么时间评估了哪个 flag(Relay Proxy 自带 HTTP 日志 + exporter 支持 Kafka/S3)
- 想用 Slack webhook 监控 flag 变更,但本地 client 不支持通知回调
注意:Relay Proxy 启动后,Go 代码要换成 OpenFeature SDK(不是 go-feature-flag 原生 client),否则连不上。迁移成本不高,但得改 import 和初始化方式。
PollingInterval 设太短反而拖垮服务?
默认 60 秒足够,设成 3 秒看似“更实时”,实则埋雷。go-feature-flag 的轮询是同步阻塞式 HTTP 请求(即使你用 file retriever,它内部仍走 polling loop)。
- 每 3 秒发起一次完整配置拉取+解析+规则重载,对磁盘 I/O 或远程存储(如 S3/GitHub)造成持续压力
- 如果配置文件大(>1MB)或规则复杂(嵌套 targeting + multiple percentage rules),单次评估耗时可能超过 100ms,高频轮询会堆积 goroutine
- 真正需要秒级响应的场景,应该用
notifier+ webhook 主动推送变更事件,而不是靠 polling “猜”
建议:非紧急灰度发布,保持默认 60s;A/B 测试期间可临时调到 10s;上线后立刻切回。
配置热更新这事,越“懒”越稳。真正难的从来不是怎么开开关,而是怎么让开关变的时候,没人感知到它变了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











