功能开关

用特性标志实现渐进启用、A/B 与紧急关闭;指导 Agent 在代码与运维两侧对齐命名、默认值、审计与清理策略。

SKILL 应区分发布开关(release toggle)、实验开关与运维开关(kill switch),并规定评估上下文:按用户、租户、百分比或环境分支,避免在热路径做远程同步阻塞。

要求记录谁可改、变更是否需审批、是否与配置中心或 LaunchDarkly 等系统同步,以及关闭后旧代码路径的测试义务,防止「永远开着的临时开关」。

类型与评估上下文

与发布流程结合:新功能默认 off,灰度阶段观测错误率与延迟,全量后设定移除日期或技术债工单,由 Agent 在 PR 中提示过期标志位。

  • 默认值须对「配置服务不可用」有安全退化(通常保守关闭新行为)。
  • 禁止用开关隐藏未完成的鉴权或支付等合规路径。
  • 文档中列出当前生产关键开关清单与负责人。
// LaunchDarkly Node.js SDK 集成示例
import * as ld from '@launchdarkly/node-server-sdk';

const client = ld.init(process.env.LD_SDK_KEY!);
await client.waitForInitialization();

// 评估上下文:按用户 + 组织 + 环境
const context: ld.LDContext = {
  kind: 'multi',
  user: { key: userId, email: user.email, plan: user.plan },
  org:  { key: orgId,  tier: org.tier },
};

// Release Toggle:新功能默认 off
const newCheckout = await client.variation(
  'billing.new-checkout-flow',   // flag key(规范化命名)
  context,
  false                          // 降级默认值(配置服务不可达时)
);

if (newCheckout) {
  return handleNewCheckout(cart);
} else {
  return handleLegacyCheckout(cart);  // 旧路径必须保留至 flag 移除
}

// Ops Toggle(Kill Switch):紧急熔断,无需重新部署
// 在控制台/API 将 flag 设为 false 即可立即生效
// Unleash Node.js SDK 集成示例(开源替代)
import { initialize } from 'unleash-client';

const unleash = initialize({
  url: 'https://unleash.internal/api/',
  appName: 'myapp',
  customHeaders: { Authorization: process.env.UNLEASH_TOKEN! },
});

// 功能开关类型示例
// release:新功能上线控制
const isNewUI = unleash.isEnabled('myapp.new-dashboard-ui', {
  userId: String(user.id),   // 按用户 ID 分桶(稳定哈希)
});

// experiment:A/B 测试,返回变体值
const variant = unleash.getVariant('myapp.checkout-button-color', {
  userId: String(user.id),
});
const buttonColor = variant.enabled ? variant.payload?.value : 'blue';

// ops:运维控制,按环境区分
const rateLimitEnabled = unleash.isEnabled('ops.strict-rate-limit');

渐进发布(Rollout)

从内部/金丝雀到百分比或分桶全量:每一步都要有可观测指标与回滚预案;评估应带稳定上下文(用户 id、租户、请求特性),避免每次随机抖动导致体验不一致。

  [ 定义标志:默认 off、命名空间、负责人 ]
        │
        ▼
  ┌─────────────┐     内测 / 固定 allowlist;验证功能与降级路径
  │  小范围启用   │
  └─────────────┘
        │
        ▼
  ┌─────────────┐     按百分比或分桶;盯错误率、延迟、业务漏斗
  │  灰度扩大    │──── 异常:降百分比或一键回 off(见 Kill switch)
  └─────────────┘
        │
        ▼
  ┌─────────────┐     全量 on 后:定移除日期或跟进工单,删死代码路径
  │  稳定与退役   │
  └─────────────┘

Agent 生成调用点时,应显式默认分支(off 时行为)、缓存/批处理对一致性的影响,以及是否与实验曝光去重逻辑冲突。

紧急熔断(Kill switch)

运维开关用于事故或异常负载时快速关闭新路径:变更须可审计、传播延迟可预期(客户端缓存 TTL、CDN、多区域),并验证关闭后核心链路仍可用。

  [ 告警 / 人工判断:需立即止血 ]
        │
        ▼
  ┌─────────────┐     在配置中心或控制台将标志置 off(或安全默认值)
  │  关闭新行为   │──── 记录操作者、工单号、时间戳
  └─────────────┘
        │
        ▼
  ┌─────────────┐     等待缓存/实例刷新;抽样验证关键用户旅程
  │  传播与验证   │
  └─────────────┘
        │
        ▼
  ┌─────────────┐     根因修复前保持 off;复盘是否需永久移除该开关
  │  事故跟进    │
  └─────────────┘
  • 关键路径禁止「只有新实现、无旧路径」——熔断后不能 500 或空白页。
  • 与 on-call 手册对齐:哪个开关对应哪条产品能力、谁有权限改生产。

治理、默认值与清理

统一命名前缀(团队/域)、环境与层级(默认 / 覆盖),避免同一语义多个键。PR 审查检查:是否新增永久 if、是否缺少测试覆盖 off 与 on 双路径。

  • 长期存在的标志应有业务 owner 与季度盘点;实验类须有过期时间。
  • 与 CI:可对过期注释或 TODO(FLAG_REMOVE_BY)做 lint 或定期报表。
// 测试中设置功能开关状态(Jest 示例)
import { FeatureFlagClient } from '../lib/feature-flags';

// 方式 1:mock 整个 SDK 客户端
jest.mock('../lib/feature-flags');
const mockClient = FeatureFlagClient as jest.Mocked;

describe('Checkout with new-checkout-flow flag', () => {
  beforeEach(() => jest.clearAllMocks());

  it('使用新版本当 flag=ON', async () => {
    mockClient.prototype.isEnabled.mockResolvedValue(true);
    const result = await processCheckout(cart);
    expect(result.flow).toBe('new');
  });

  it('回退到旧版本当 flag=OFF(降级路径必须测试)', async () => {
    mockClient.prototype.isEnabled.mockResolvedValue(false);
    const result = await processCheckout(cart);
    expect(result.flow).toBe('legacy');
  });

  it('配置服务不可达时使用默认值 false', async () => {
    mockClient.prototype.isEnabled.mockRejectedValue(new Error('timeout'));
    const result = await processCheckout(cart);
    expect(result.flow).toBe('legacy');  // 降级默认值
  });
});

标志键规范化

将草稿名称转为稳定键:小写、连字符分词、仅保留 a-z0-9.-(便于与多数 SDK 及配置中心兼容)。下方输入即会规范化,空输入表示非法键。

规则:trim → 小写 → 空白与下划线合并为单个 - → 去掉非法字符 → 合并连续 - → 去掉首尾 -

规范化结果

                

若结果为空,说明去掉非法字符后无有效键;团队可在此基础上加固定前缀(如 billing.)以区分域。

---
name: feature-flags
description: 功能开关类型、SDK 集成、测试与生命周期治理
version: 2.0
---
# 开关类型与命名约定
- release:    team.feature-name         (默认 off,发布后移除)
- experiment: team.exp-button-color     (有过期日期,配套统计分析)
- ops:        ops.strict-rate-limit     (运维熔断,需审计变更)
- permission: billing.enterprise-only  (按角色/租户授权)

# SDK 评估最佳实践
- 评估上下文:user.key + org.key + env(保证稳定分桶)
- 降级默认值:配置服务不可达时保守关闭新行为
- 热路径:用本地缓存(TTL 30s)避免同步远程调用阻塞
- 禁止:在循环或 ORM hook 中高频调用远程 SDK

# 生命周期管理
- 创建:PR 中添加 FLAG_OWNER 和 FLAG_REMOVE_BY 注释
- 激活:灰度 → 观测指标 → 推进百分比
- 清理:全量后 30 天内提 PR 删除 flag 代码与 SDK 调用
- CI Lint:检查代码中超过 FLAG_REMOVE_BY 日期的 flag 调用

# 测试双路径
- flag=true 路径:新功能行为验证
- flag=false 路径:降级/旧路径必须有独立测试用例
- SDK 不可达:confirm 默认值行为符合预期

返回技能库 更多技能入口