feat(flags): PUT /operator/feature-flags 真持久化(V048)
此前 updateFlag 只改 FeatureFlagConfig 内存单例的字段:重启即回默认值、 多实例互不一致,表现为「后台显示已关闭,一次发布后功能又回来了」。 - V048 新建 feature_flag_overrides(flag_key 主键;值存字符串、回读按字段 声明类型解析;updated_by 记审计)。updated_by 必须建 uuid 而非 varchar, 否则 UUIDStringTypeHandler 以 uuid 发参数会在 PG 抛 operator does not exist: character varying = uuid(同 V046 的 actor_id)。 - FeatureFlagOverride/Mapper/Service:upsert 走「先 UPDATE、0 行再 INSERT」, 不用 PG 的 ON CONFLICT(H2 测试库不认,同 IdempotencyMapper 取舍)。 - FeatureFlagConfig.reloadFromPersistence() 挂 @PostConstruct:该时机晚于 @ConfigurationProperties 绑定,故 DB 覆盖压得住 yml 默认值。 - PUT 先改内存再落库(内存改动失败即 400,不写库);新增 DELETE 恢复默认。 - 覆盖值无法解析时启动 fail-fast,不静默回退默认(否则「配了不生效」)。 守卫 FeatureFlagPersistenceGuardTest 11 例,核心是「另起实例重新加载后改动仍在」 (重启等价路径),并自检 @PostConstruct 未被摘掉。 负向验证:注入不落库 + 摘钩子 -> 恰好 5 例变红,其余不受影响;还原 md5 一致。 全量回归 700 / 0 / 0 / 3(起点 689,净 +11);UI 契约门禁 18/18。
This commit is contained in:
@@ -633,3 +633,16 @@ CREATE TABLE review_items (
|
||||
|
||||
CREATE UNIQUE INDEX uk_idempotency_scope
|
||||
ON idempotency_records (actor_id, endpoint, idempotency_key);
|
||||
|
||||
-- V048: Feature Flag 运行期覆盖持久化
|
||||
-- 生产 updated_by 是 uuid(UUIDStringTypeHandler 以 uuid 类型发送参数,
|
||||
-- 建成 varchar 会在 PG 上报 operator does not exist,同 V046 的 actor_id);
|
||||
-- H2 侧沿用本库既有约定的 VARCHAR(36)。
|
||||
CREATE TABLE feature_flag_overrides (
|
||||
flag_key VARCHAR(64) PRIMARY KEY,
|
||||
flag_value VARCHAR(255) NOT NULL,
|
||||
value_type VARCHAR(16) NOT NULL,
|
||||
updated_by VARCHAR(36),
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT chk_flag_value_type CHECK (value_type IN ('boolean', 'int', 'string'))
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user