Repository navigation
[C294] Capability 能力注入机制重设计(破坏性一次性切换) #622
Copy link
Copy link
Closed
Labels
P2Priority 2 (medium)Priority 2 (medium)project:gameframex.server.sourceSynced from SonarQube CloudSynced from SonarQube Cloud
Description
背景
Capability 能力尚未上线,没有存量部署和外部调用方。按 B佬 裁定(2026-10-23),这次对能力注入机制做破坏性一次性切换:不留兼容层、不分期、不保留旧入口签名,旧机制在同一个 change 里整体删除。
保留项只按正确性和架构护栏保留:12 包拓扑、GFX0017、三条装配红线(manifest Id 唯一 / 依赖闭包失败即停 / job 全名唯一)、--AllInOne --DatabaseProvider=Sqlite 零依赖起跑、桥撤销后显式返回 DependencyUnavailable(8002)。
问题
- 模块只有
Register一个钩子,没有启停生命周期,桥的发布与撤销只能外泄到AppStartUpGame。 - 桥协议同型复制 4 份(Friend / MatchGame / MatchDomain / Session),每加一个域都要手写 holder + lease + Wiring + 组合根编排。C241 代码审查把它列为头号高风险:GFX0018 按名字清单判定,已经漏掉了 Session 这一族。
- 服务注册按类型单键单实例,替换实现靠"组合根先
UseService、模块再TryGetService探测"的时序约定,探测不到就静默回退 InMemory / Empty 实现。 - 族组合根硬编码 Online 具型,admin 组装散落在 Launcher;admin action 同名时静默覆盖。
- 机制层事件口
CapabilityEventJob/RaiseEvent生产零调用,业务事件另走InMemoryEventPublisher。 - 包级 Options 全是空类;模块构造服务时传
null,服务内?? new XxxOptions()兜底,生产只能跑默认值。 - manifest 依赖声明与代码用法不一致:7 条依赖在代码里按可选写,manifest 却声明成必选。装配过程不打日志,成环时也不列出环上的能力。
- 调度器 tick job 没有 per-job 隔离,异常被吞且零日志,时钟不可注入。
证据
GameFrameX.Launcher/Online/OnlineCapabilityComposition.cs:116-213:AddOnlineCapabilities与BuildScannedRuntime预置 Online 具型GameFrameX.Launcher/StartUp/AppStartUpGame.cs:249-361:四桥手工 Publish / RetractCapability/GameFrameX.Capability.Online.Abstractions/Bridges/:4 对 holder / leaseCapability/GameFrameX.Capability.Hosting.Core/CapabilityHostBuilder.cs:193-236:拓扑定序遇到第一个缺失就抛出;:213同层顺序取决于扫描顺序Capability/GameFrameX.Capability.Hosting.Core/CapabilityScheduler.cs:279:空 catchCapability/GameFrameX.Capability.Hosting.AdminApi/AdminActionRegistry.cs:57:同名 action 静默覆盖OnlineCompetitionCapabilityModule.cs:114、OnlineMatchmakingCapabilityModule.cs:105-106:构造服务时传nullOptionsOnlineMatchCapabilityModule.cs:103-117、OnlineCompetitionCapabilityModule.cs:121-135、OnlineOperationsCapabilityModule.cs:138-142:声明为必选,代码按可选探测
期望行为
- 模块契约改为 Register / Activate / Deactivate 三段;激活中途失败时逆序回滚;桥发布、榜单预建、撮合通知订阅迁入所属模块。
- 桥改为机制层泛型
CapabilityBridge<T>,宿主停止时自动撤销;删除 8 个 holder / lease 文件和 4 个 Wiring。 - 服务注册改为描述符表(类型 + 命名 + 懒工厂 + 来源),替换实现走显式
Override<T>;删除TryGetService和全部探测回退。 - 族组合骨架
CapabilityComposition.Compose取代AddOnlineCapabilities;admin 组装上移到 Hosting.AdminApi,同名 action 直接失败。 - 两条事件通道合为机制层事件总线,topic 统一为
<族>.<域>.<事件>。 - 启动模板新增
ComposeCapabilitiesAsync(热更装载之后、网络监听之前);"Online" 配置段声明EnableRoles,IsEnableOnline/IsEnableOnlineAdmin并入该配置段。 - 调度器做 per-job 隔离,支持时钟注入,并输出指标。
- 参数默认值只在能力包 Options 内定义;装配时按"包内默认 → 配置段
Online.Settings→ 代码Configure"逐字段覆盖,再执行Validate;未知能力 Id 或未知字段直接失败。回调按实现方分三类注入:能力间依赖、宿主扩展点、Hotfix 钩子(CapabilityHook<T>)。 - 依赖分必选 / 可选,在任何模块
Register之前统一检查:- 必选缺失或成环:打 Error 并装配失败,所有问题一次报全。
- 可选缺失:打 Info,写明"缺失功能「…」,不影响 … 其余功能运行"。
- 同层按能力 Id 排序。
依赖边调整(已确认):
| 能力 | 必选 | 可选 |
|---|---|---|
| online-social | online-foundation | — |
| online-matchmaking | online-social | — |
| online-match | — | online-assets、online-matchmaking |
| online-competition | — | online-assets、online-match |
| online-operations | online-foundation | online-assets、online-social、online-match、online-matchmaking |
范围外:12 包拓扑增删、三套发现机制统一、C204 双会话、热更 ALC 钉扎、Options 运行期热改。
验收检查
- 清理 bin/obj 后
dotnet build Server.slnx --no-incremental0 错误、0 新增警告,GFX0017 / GFX0018 0 违规 - 全量测试全绿;新增用例覆盖生命周期回滚、桥撤销后 8002、依赖检查(必选 Error / 可选 Info / 一次报全 / 环路路径 / 与发现顺序无关)、Options 三层覆盖与失败场景、钩子挂载 / 替换 / 释放
-
--AllInOne --DatabaseProvider=Sqlite冒烟 0 异常;好友 120/660、匹配 420、RPS 对局结算、会话恢复四条链路走通;退出后桥全部撤销 - 排除
online-assets时启动成功并输出可选缺失 Info;排除online-foundation时启动失败,并列出全部受影响能力 - 全仓 grep 零残留:
AddOnline、UseOnline、UseService、BridgeHolder、BridgeLease、TryGetService、RaiseEvent、IsEnableOnline
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P2Priority 2 (medium)Priority 2 (medium)project:gameframex.server.sourceSynced from SonarQube CloudSynced from SonarQube Cloud
Activity
linear-code commentedon Oct 23, 2026
GFX-998
AlianBlank commentedon Oct 24, 2026
由 #623 完成(已合并)。PR 正文当时只写了
Linear: GFX-998,不是 GitHub 关闭关键字,因此未自动关闭,此处手工补关。