远程配置与 Feature Flags
远程配置(Remote Config)/ 功能开关(Feature Flag)让你不发版就能改变线上行为:在 Console 定义
flag 与定向规则,端上 SDK 周期拉取并本地缓存,业务代码用 getBoolean("new_ui", false) 这类
永不抛异常、永不返回空的 API 取值。最典型的用法是 kill switch——新功能出问题时在 Console
把开关关掉,等客户端下一次刷新即可止血,无需紧急发版。
服务端实现在 services/config
(flag 定义、targeting 求值、GET /v1/config 下发)。PRD:
docs/02-product/25-remote-config.md。
核心概念
Flag 类型
| 类型 | 取值 | 典型用途 |
|---|---|---|
boolean | on / off | 功能开关、kill switch |
string | 任意字符串 | 文案、主题名、API 版本号 |
number | 数值 | 阈值、超时、列表长度 |
json | 对象或数组 | 复杂结构化配置(如页面布局) |
开关(enabled)语义
- boolean flag:未命中任何规则时,取值 = 顶部开关状态(开 =
true,关 =false)。 - string / number / json flag:开启时未命中规则下发
default_value(服务端默认值); 关闭即不下发——客户端取到代码里的 default,这就是类型化 flag 的 kill switch 行为。
Targeting 规则
每个 flag 可挂多条规则,按优先级(position)从上到下首个命中胜出:
- 匹配属性:
platform(如ios/android/web)或app_version(如2.3.0),等值匹配。 - 命中返回值:boolean flag 返回 on / off;类型化 flag 返回一个符合声明类型的值。
- 无规则命中 → 落到上面的 enabled / 默认值语义。
按百分比灰度放量(一致性 hash 分桶)、按 user attribute / region 定向、复合 AND / OR 规则为 规划中能力(版本级的百分比灰度已可用,见 版本与灰度发布)。
取值优先级:远程 > 缓存 > default(永不返回空)
SDK 的每次 getXxx(key, default) 按以下顺序回退,绝不返回 null / 绝不抛异常 / 绝不阻塞启动:
- 本次进程内已成功拉取并通过类型校验的最新远程值;
- 上次成功拉取的持久化缓存(跨启动存活);
- 调用方传入的 default(最后兜底)。
配套行为:拉取失败保留旧缓存(不回退 default,避免服务端抖动引发全网行为闪烁);
远程值类型与取值 API 不匹配(如远程下发字符串但代码取 boolean)时跳过该值回退;
Argus.init() 与首次取值不等待网络——冷启动有缓存用缓存、无缓存用 default,远程值后台
拉取成功后于下次取值生效。
生效时延(重要预期管理)
Console 上的修改立即写入服务端(控制平面实时),但已在运行的客户端要到 下一次后台刷新(默认 30 分钟,可配)或下次冷启动才拿到新值。紧急止血场景请把轮询间隔调短, 或等待实时推送(SSE,规划中)上线。
接入
平台矩阵
远程配置取值在 5 个端上 SDK 全部可用;5 个后端 SDK(Go / Node / Python / Java / Rust) 均未实装 Remote Config 拉取(目标 API 见 后端 SDK 对照表 §6 ), 当前请以端上消费为主。
| 平台 | 开启方式 | 取值 API 前缀 | 快速开始 |
|---|---|---|---|
| Web | Argus.init({ ..., remoteConfig: true }) | Argus.config.getXxx | /quickstart/web/ |
| iOS | ArgusConfig.remoteConfig = true | Argus.configGetXxx | /quickstart/ios/ |
| Android | ArgusConfig.Builder(dsn).remoteConfig(true) | Argus.configGetXxx | /quickstart/android/ |
| Flutter | ArgusConfig(..., remoteConfig: true) | Argus.configGetXxx | /quickstart/flutter/ |
| React Native | Argus.init({ ..., remoteConfig: true }) | Argus.config.getXxx | /quickstart/react-native/ |
开启后 SDK 启动拉取一次 GET /v1/config 并按默认 30 分钟间隔后台轮询(间隔可在 init 配置,
如 iOS configPollInterval / Android configPollIntervalSeconds),结果持久化缓存。
拉取时携带 platform / app_version 等上下文,服务端按 targeting 规则求值后下发键值快照。
最小接入片段
Web
Argus.init({ dsn: "argus://...", remoteConfig: true });
const newUI = Argus.config.getBoolean("new_ui_enabled", false);
const theme = Argus.config.getString("theme", "light");
const layout = Argus.config.getJSON("checkout_layout", {});永远给 getXxx 传一个业务上安全的 default——它是断网、首启无缓存、类型不匹配时的最终兜底。
上报与拉取的鉴权凭证见 DSN 与 HMAC。
Console 使用
进入 Console 左侧导航 Feature Flags 页(先在左上角选择项目):
- 新建 Flag:填 key(如
new_ui)、描述(可选)、类型(boolean / string / number / json); 非 boolean 类型需填默认值(json 需为对象或数组)。key 重复返回 409 提示换名。 - 开 / 关:列表中直接勾选切换 enabled;对类型化 flag 而言”关闭 = 不下发 = kill switch”。
- 编辑规则:展开某 flag 的规则面板——选择属性(
platform/app_version)、填目标值、 设定命中时返回(boolean 选 on / off,类型化 flag 填符合类型的返回值),规则按优先级从上到下 首个命中胜出;可逐条删除。 - 删除 Flag:不可撤销,删除前二次确认。
列表字段:Key、状态(已开启 / 已关闭)、类型 / 默认值、描述、规则数、操作。
SDK API 速查
| 取值 | Web / React Native | iOS | Android | Flutter |
|---|---|---|---|---|
| Boolean | Argus.config.getBoolean(key, def) | Argus.configGetBoolean(key, def) | Argus.configGetBoolean(key, def) | Argus.configGetBoolean(key, def) |
| String | Argus.config.getString(key, def) | Argus.configGetString(key, def) | Argus.configGetString(key, def) | Argus.configGetString(key, def) |
| JSON | Argus.config.getJSON(key, def) | Argus.configGetJSON(key, def) | Argus.configGetJSON(key, def) | Argus.configGetJSON(key, def) |
| 实验变体 | Argus.config.getVariant(key, def) | Argus.configGetVariant(key, def) | Argus.configGetVariant(key, def) | Argus.configGetVariant(key, def) |
getVariant 返回该用户在 A/B 实验中被分到的变体(随配置包一起下发),详见
A/B 实验。
MCP 工具
接入 Argus MCP Server 后可让 AI 查线上配置现状
(源码:config_get.ts):
| 工具 | 用途 | 关键参数 |
|---|---|---|
config.get | 项目当前生效的远程配置:求值后的 flag 值、实验分配、生效中的灰度版本 | project_id,可选 platform / app_version(模拟某客户端上下文求值;缺省为项目默认) |
典型提问:“new_ui_enabled 在 iOS 2.3.0 上现在下发什么值?”、“当前有哪些 flag 是关着的?“
配额与计费
- 配置拉取按实际到达服务端的请求计量(约 1000 次配置请求 = 1 个计费事件,以计费页为准); SDK 本地缓存命中不产生请求、不计费——轮询间隔越长消耗越低。
- 详见 套餐、配额与计费。
FAQ
我在 Console 改了 flag,客户端为什么没变化?
已运行的客户端要到下次后台刷新(默认 30 分钟)或下次冷启动才拿到新值——这是轮询模型的预期行为。
依次排查:① init 是否开了 remoteConfig;② flag 是否 enabled、规则是否命中该 platform /
app_version;③ 取值 API 类型是否与 flag 声明类型一致(不一致会回退 default)。可用 MCP
config.get 模拟该客户端上下文核对服务端实际下发值。
断网 / 服务端不可用时取值是什么? 有缓存取缓存(上次成功拉取的值),从未拉取成功过则取 default。后台刷新失败不会把已生效的值 回退成 default。
类型化 flag 关闭后客户端取到什么? 关闭即不下发该 key,客户端落到代码 default——所以 default 应当是”功能关闭”的安全值。
支持按百分比放量吗? flag 级的百分比 rollout(一致性 hash 分桶)为规划中;当前如需按百分比灰度,可用 版本灰度发布(已支持百分比 + 定向白名单),或用 A/B 实验的权重分流。
改动能实时推送到端上吗? v1.5 为纯轮询拉取,无服务端推送;SSE / WebSocket 实时推送为规划中。对时效敏感的开关请调短 轮询间隔(代价是请求量与配额消耗上升)。