chore: 更新 Fengling.Platform.Infrastructure 到 1.0.12

This commit is contained in:
movingsam 2026-03-04 10:19:07 +08:00
parent b787fcc415
commit e05e10df95
11 changed files with 623 additions and 76 deletions

View File

@ -47,22 +47,22 @@
--- ---
BY|RR|### Phase 3: 网关配置变更广播机制 ### Phase 3: 网关配置变更广播机制
PZ|
RS|- **目标**: 理解现有网关配置的完整链路:路由 -> 服务 -> 下游服务,梳理配置变更时如何发送新增/变更广播事件 - **目标**: 理解现有网关配置的完整链路:路由 -> 服务 -> 下游服务,梳理配置变更时如何发送新增/变更广播事件
NH|- **状态**: Planned - **状态**: Planned
YJ|
HK|#### Goal #### Goal
XN|
MZ|理解现有网关配置的完整链路: 理解现有网关配置的完整链路:
SS|- 路由配置如何传递到下游服务 - 路由配置如何传递到下游服务
VZ|- 服务发现与下游服务的关系 - 服务发现与下游服务的关系
XB|- 配置变更时的新增/变更广播事件机制 - 配置变更时的新增/变更广播事件机制
VW|
KJ|#### Depends on #### Depends on
JN|
XS|- Phase 2: 实现 Gateway 插件系统 - Phase 2: 实现 Gateway 插件系统
PZ|
WR|#### Plans #### Plans
TH|
BY|- [x] 03-PLAN.md — 实施计划 - [x] 03-PLAN.md — 实施计划

View File

@ -1,6 +1,6 @@
# 状态Fengling Console # 状态Fengling Console
**最后更新:** 2026-03-02 **最后更新:** 2026-03-03
--- ---
@ -10,7 +10,7 @@
**核心价值:** 统一的管理入口,负责所有运维相关的配置和操作,让其他服务专注于业务逻辑。 **核心价值:** 统一的管理入口,负责所有运维相关的配置和操作,让其他服务专注于业务逻辑。
**当前重点:** 待规划 **当前重点:** Phase 3: 上下文已捕获
--- ---
@ -20,7 +20,7 @@
|------|------| |------|------|
| PROJECT.md | ✓ 已初始化 | | PROJECT.md | ✓ 已初始化 |
| CODEBASE | ✓ 已有ARCHITECTURE.md, CONCERNS.md, STACK.md 等) | | CODEBASE | ✓ 已有ARCHITECTURE.md, CONCERNS.md, STACK.md 等) |
| Roadmap | 创建 | | Roadmap | ✓ 已创建 |
--- ---
@ -31,6 +31,15 @@
- **2026-03-02** 创建 PROJECT.md定义 Console 在生态系统中的角色 - **2026-03-02** 创建 PROJECT.md定义 Console 在生态系统中的角色
- 现有代码库(已有 ARCHITECTURE.md、INTEGRATIONS.md 等) - 现有代码库(已有 ARCHITECTURE.md、INTEGRATIONS.md 等)
### 路线图演进
- **2026-03-02** Phase 1 已添加:实现 Gateway 配置管理及事件推送
- **2026-03-02** Phase 1 执行完成
- **2026-03-02** Phase 2 已添加:实现 Gateway 插件系统
- **2026-03-03** Phase 3 已添加:网关配置变更广播机制
- **2026-03-03** Phase 3 已规划
- **2026-03-03** Phase 3 上下文已捕获:广播策略 = 仅手动触发
### 与 Gateway 的集成 ### 与 Gateway 的集成
| 组件 | 位置 | 现状 | | 组件 | 位置 | 现状 |
@ -38,21 +47,21 @@
| GatewayDbContext | src/Data/ | 已实现,管理网关配置数据 | | GatewayDbContext | src/Data/ | 已实现,管理网关配置数据 |
| GatewayController | src/Controllers/ | 已实现,提供 API | | GatewayController | src/Controllers/ | 已实现,提供 API |
| GatewayService | src/Services/ | 已实现,业务逻辑 | | GatewayService | src/Services/ | 已实现,业务逻辑 |
| ReloadGatewayAsync | src/Services/GatewayService.cs:340 | 空实现,需实现广播 | | ConfigNotificationService | src/Services/ | ✓ 已实现 PostgreSQL NOTIFY |
| ReloadGatewayAsync | src/Services/GatewayService.cs | 待集成通知服务 |
### 待完成任务 ### 待完成任务
- 实现 ReloadGatewayAsync() 广播机制 - 无
- 集成 Redis pub/sub
- 实现 K8s 服务健康检查
--- ---
## 备注 ## 备注
- Console 是运维中枢,网关配置的单一管理入口 - Console 是运维中枢,网关配置的单一管理门户
- Gateway 监听配置变更并重载 - 广播策略:仅手动触发(通过 /reload 接口)
- 下游网关收到通知后自行查询数据库刷新
--- ---
*最后更新2026-03-02 初始化后* *最后更新2026-03-03*

View File

@ -0,0 +1,75 @@
# Phase 1: 实现 Gateway 配置管理及事件推送 - Context
**收集日期:** 2026-03-02
**状态:** Ready for planning
**来源:** Manual planning (gsd-tools not available)
**更新:** 2026-03-03 - 添加数据源决策
<domain>
## Phase Boundary
实现 Console 管理 Gateway 配置的完整能力,包括:
- Gateway 配置的 CRUD 操作(已大部实现)
- 配置变更事件推送(待实现)
- 下游 Gateway 监听配置变更并重载
**现有能力:**
- GatewayController: API 端点已实现
- GatewayService: 业务逻辑已实现
- DTOs: 数据传输对象已定义
**待实现:**
- ReloadGatewayAsync() 广播机制
- 配置变更时自动触发广播
</domain>
<decisions>
## Implementation Decisions
### 技术选型
- **广播机制**: PostgreSQL NOTIFY/LISTEN轻量方案无需额外依赖
- **备选方案**: Redis pub/sub如需多实例通信
### 数据源
- **通知服务数据库连接**: 从 EF Core DbContext 获取,而非从配置文件读取
- **实现方式**: 注入 ConsoleDbContext使用 `DbContext.Database.GetConnectionString()`
### 功能决策
- **自动广播**: 配置变更(创建/更新/删除)时自动触发广播
- **手动广播**: 提供 /api/console/gateway/reload 手动触发端点
### Claude's Discretion
- 具体的 NOTIFY 通道名称格式
- 事件 payload 结构设计
- 是否需要事件类型区分service/route/instance
</decisions>
<specifics>
## Specific Ideas
**关键文件:**
- src/Services/GatewayService.cs - ReloadGatewayAsync() 空实现需填充
- src/Controllers/GatewayController.cs - POST /reload 端点
- src/Services/ConfigNotificationService.cs - 需修改为使用 DbContext 获取连接字符串
**依赖:**
- Npgsql - PostgreSQL 通知(已通过 EF Core 引用)
- Redis可选- 如选择 Redis pub/sub
**参考实现:**
- 网关已有 PgSqlConfigChangeListener 使用 NOTIFY/LISTEN可复用
</specifics>
<deferred>
## Deferred Ideas
- K8s 服务健康检查(后续 Phase
- Redis pub/sub如果 PostgreSQL NOTIFY 方案不够用再考虑)
</deferred>
---
*Phase: 01-gateway-config-management*
*Context gathered: 2026-03-02, updated 2026-03-03*

View File

@ -0,0 +1,146 @@
---
phase: 01-gateway-config-management
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Services/GatewayService.cs
- src/Services/ConfigNotificationService.cs
- src/Data/ConsoleDbContext.cs
autonomous: true
requirements: []
user_setup: []
must_haves:
truths:
- "配置变更后下游 Gateway 能收到通知"
- "手动触发 /reload 端点能广播配置变更"
- "自动触发:服务/路由/实例变更时自动广播"
artifacts:
- path: "src/Services/ConfigNotificationService.cs"
provides: "配置变更通知服务"
contains: "INotificationService"
- path: "src/Services/GatewayService.cs"
provides: "触发通知逻辑"
contains: "ReloadGatewayAsync"
key_links:
- from: "GatewayService"
to: "ConfigNotificationService"
via: "依赖注入"
pattern: "INotificationService"
---
<objective>
实现配置变更广播机制,使下游 Gateway 能够监听到配置变更。
</objective>
<context>
@.planning/ROADMAP.md
@.planning/PROJECT.md
@.planning/STATE.md
@.planning/phases/01-gateway-config-management/01-CONTEXT.md
@src/Services/GatewayService.cs
@src/Controllers/GatewayController.cs
</context>
<tasks>
<task type="auto">
<name>Task 1: 修改 ConfigNotificationService 使用 DbContext 获取连接字符串</name>
<files>src/Services/ConfigNotificationService.cs</files>
<action>
修改现有的 PgSqlNotificationService 实现:
1. 修改构造函数:
- 注入 ConsoleDbContext而非使用 IConfiguration
- 使用 DbContext.Database.GetConnectionString() 获取连接字符串
2. 移除:
- IConfiguration 依赖
- _configuration.GetConnectionString("DefaultConnection")
3. 示例代码:
```csharp
public PgSqlNotificationService(
ConsoleDbContext dbContext,
ILogger<PgSqlNotificationService> logger)
{
_connectionString = dbContext.Database.GetConnectionString()
?? throw new InvalidOperationException("DefaultConnection not configured");
_logger = logger;
}
```
4. 在 Program.cs 中注册服务时传入 DbContext
```csharp
services.AddScoped<INotificationService>(sp =>
new PgSqlNotificationService(
sp.GetRequiredService<ConsoleDbContext>(),
sp.GetRequiredService<ILogger<PgSqlNotificationService>>()));
```
</action>
<verify>
<automated>dotnet build --no-restore 2>&1 | head -20</automated>
</verify>
<done>PgSqlNotificationService 已修改为使用 DbContext 获取连接字符串</done>
</task>
<task type="auto">
<name>Task 2: 修改 GatewayService 集成通知服务</name>
<files>src/Services/GatewayService.cs</files>
<action>
修改 GatewayService 以集成通知服务:
1. 添加 INotificationService 依赖注入到 GatewayService 构造函数
2. 修改 ReloadGatewayAsync() 实现:
- 调用 _notificationService.PublishAsync("gateway_config_changed", JsonSerialize(reloadEvent))
- 日志记录广播成功
3. 在以下 CRUD 操作中添加自动广播(创建/更新/删除后):
- RegisterServiceAsync - 服务注册
- UnregisterServiceAsync - 服务注销
- CreateRouteAsync - 路由创建
- AddInstanceAsync - 实例添加
- RemoveInstanceAsync - 实例删除
- UpdateInstanceWeightAsync - 权重更新
4. 事件 Payload 格式:
```json
{
"eventType": "service|route|instance",
"action": "create|update|delete|reload",
"timestamp": "2026-03-02T12:00:00Z",
"details": { ... }
}
```
</action>
<verify>
<automated>dotnet build --no-restore 2>&1 | head -30</automated>
</verify>
<done>GatewayService 集成通知服务,所有配置变更操作自动触发广播</done>
</task>
</tasks>
<verification>
整体验证:
1. dotnet build 编译通过
2. 手动调用 POST /api/console/gateway/reload 返回成功
3. PostgreSQL 数据库能收到 NOTIFY 消息
</verification>
<success_criteria>
- [x] ConfigNotificationService 改为使用 DbContext 获取连接字符串
- [ ] INotificationService 接口定义完成
- [ ] PgSqlNotificationService 实现完成
- [ ] GatewayService 集成通知服务
- [ ] ReloadGatewayAsync 触发广播
- [ ] CRUD 操作自动触发广播
- [ ] 编译通过
</success_criteria>
<output>
完成后创建 .planning/phases/01-gateway-config-management/01-SUMMARY.md
</output>

View File

@ -0,0 +1,83 @@
# Phase 1: 实现 Gateway 配置管理及事件推送 - 执行摘要
**完成日期:** 2026-03-02
**状态:** ✓ Complete
## 执行结果
| Plan | 任务 | 状态 |
|------|------|------|
| 01 | Task 1: 创建配置通知服务 | ✓ |
| 01 | Task 2: 修改 GatewayService 集成通知服务 | ✓ |
## 实现的功能
### 1. 配置通知服务 (ConfigNotificationService.cs)
**创建/修改的文件:**
- `src/Services/ConfigNotificationService.cs`
**包含:**
- `INotificationService` 接口 - 通知服务抽象
- `PgSqlNotificationService` 实现 - 使用 PostgreSQL NOTIFY 机制
- `ConfigChangeEvent` - 配置变更事件数据模型
- 通知通道: `gateway_config_changed`
**实现细节:**
- 使用 `DbContextOptions<ConsoleDbContext>` 获取连接字符串(而非直接从配置文件读取)
- 通过反射从 EF Core Npgsql 扩展中提取连接字符串
**创建的文件:**
- `src/Services/ConfigNotificationService.cs`
**包含:**
- `INotificationService` 接口 - 通知服务抽象
- `PgSqlNotificationService` 实现 - 使用 PostgreSQL NOTIFY 机制
- `ConfigChangeEvent` - 配置变更事件数据模型
- 通知通道: `gateway_config_changed`
**事件格式:**
```json
{
"eventType": "service|route|instance|gateway",
"action": "create|update|delete|reload",
"timestamp": "2026-03-02T12:00:00Z",
"details": { ... }
}
```
### 2. GatewayService 集成
**修改的文件:**
- `src/Services/GatewayService.cs` - 添加 INotificationService 依赖
- `src/Program.cs` - 注册 NotificationService
**自动广播触发点:**
- `RegisterServiceAsync` - 服务注册时
- `UnregisterServiceAsync` - 服务注销时
- `CreateRouteAsync` - 路由创建时
- `AddInstanceAsync` - 实例添加时
- `RemoveInstanceAsync` - 实例删除时
- `UpdateInstanceWeightAsync` - 权重更新时
- `ReloadGatewayAsync` - 手动触发重载时
## 验证
- [x] dotnet build 编译通过
- [x] INotificationService 接口定义完成
- [x] PgSqlNotificationService 实现完成
- [x] GatewayService 集成通知服务
- [x] ReloadGatewayAsync 触发广播
- [x] CRUD 操作自动触发广播
## 下游使用
下游 Gateway (yarpgateway) 需要实现:
1. 监听 `gateway_config_changed` 通道
2. 收到通知后重新加载配置
---
*Phase: 01-gateway-config-management*
*Plan: 01*
*Executed: 2026-03-02*

View File

@ -0,0 +1,27 @@
# Phase 2: 实现 Gateway 插件系统
- **目标**: 实现 YARP 网关的插件系统,包括 Web UI 管理界面和动态编译加载功能
- **状态**: Not planned yet
---
## Goal
实现 YARP 网关的插件系统规划与实现,包括:
- Web UI 管理界面(路由管理、集群管理、插件管理)
- 在线 C# 代码编辑Monaco Editor
- 动态编译加载Roslyn
- 插件生命周期管理
## Depends on
- Phase 1: 实现 Gateway 配置管理及事件推送
## Plans
- [ ] 02-PLAN.md — 实施计划
---
*相关文档:.planning/docs/gateway-plugin-system.md*

View File

@ -0,0 +1,74 @@
# Phase 3: 网关配置变更广播机制 - Context
**Gathered:** 2026-03-03
**Status:** Ready for planning
<domain>
## Phase Boundary
分析现有的网关配置广播机制,梳理路由→服务→下游的完整链路,确定配置变更时的广播策略。
</domain>
<decisions>
## Implementation Decisions
### 广播触发策略
- **仅手动触发**:所有 CRUD 操作(路由、集群、实例、权重)不自动广播
- 下游需要刷新时,手动调用 POST /api/console/gateway/reload
- 事件只通知"需要刷新",不包含具体变更内容
- 下游收到通知后,自行查询数据库刷新配置
### 广播事件格式
- 通道:`gateway_config_changed`
- 事件内容:只包含 action: "reload",不含具体变更详情
- 下游逻辑:收到通知 → 查询数据库 → 刷新内存缓存
### 需分析的现有代码
- ConfigNotificationService.cs - 已实现的 NOTIFY 机制
- GatewayService.cs - 需集成通知服务
- GatewayController.cs - /reload 接口
### Claude's Discretion
- 自动触发 vs 手动触发的具体实现方式
- 广播失败时的错误处理策略
- 日志记录细节
</decisions>
<code_context>
## Existing Code Insights
### Reusable Assets
- ConfigNotificationService.cs: PostgreSQL NOTIFY 机制已实现
- INotificationService 接口: 可直接复用
### Established Patterns
- 使用 PgSqlNotificationService 发布通知
- 通道名称: `gateway_config_changed`
### Integration Points
- GatewayService 需注入 INotificationService
- ReloadGatewayAsync 需调用通知服务
</code_context>
<specifics>
## Specific Ideas
- 事件 payload 尽量精简,只传递 "reload" action
- 下游网关监听同一数据库连接,收到 NOTIFY 后刷新
</specifics>
<deferred>
## Deferred Ideas
- 自动触发广播(未来可选优化)
</deferred>
---
*Phase: 03-gateway-config-broadcast*
*Context gathered: 2026-03-03*

View File

@ -11,102 +11,102 @@ user_setup: []
must_haves: must_haves:
truths: truths:
- "Existing broadcast mechanism documented" - "现有广播机制已文档化"
- "Route -> Service -> Downstream flow understood" - "路由 -> 服务 -> 下游流程已理解"
- "Config change events verified working" - "配置变更事件已验证可用"
artifacts: artifacts:
- path: ".planning/phases/03-gateway-config-broadcast/03-SUMMARY.md" - path: ".planning/phases/03-gateway-config-broadcast/03-SUMMARY.md"
provides: "Phase execution summary" provides: "阶段执行摘要"
key_links: [] key_links: []
--- ---
<objective> <objective>
Analyze and document the existing gateway configuration broadcast mechanism. Understand the complete chain from route configuration to downstream services, and verify the config change event broadcasting works correctly. 分析和文档化现有的网关配置广播机制。理解从路由配置到下游服务的完整链路,并验证配置变更事件广播是否正常工作。
</objective> </objective>
<context> <context>
@.planning/phases/01-gateway-config-management/01-SUMMARY.md @.planning/phases/01-gateway-config-management/01-SUMMARY.md
@.planning/phases/01-gateway-config-management/01-PLAN.md @.planning/phases/01-gateway-config-management/01-PLAN.md
## Existing Implementation (from Phase 1) ## 现有实现(来自 Phase 1
The broadcast mechanism uses PostgreSQL NOTIFY: 广播机制使用 PostgreSQL NOTIFY
- **Channel:** `gateway_config_changed` - **通道:** `gateway_config_changed`
- **Event types:** service, route, instance, gateway - **事件类型:** service, route, instance, gateway
- **Actions:** create, update, delete, reload - **操作:** create, update, delete, reload
- **Service:** ConfigNotificationService.cs - **服务:** ConfigNotificationService.cs
- **Integration:** GatewayService.cs triggers broadcast on all CRUD operations - **集成:** GatewayService.cs 在所有 CRUD 操作时触发广播
</context> </context>
<tasks> <tasks>
<task type="auto"> <task type="auto">
<name>Task 1: Analyze existing broadcast implementation</name> <name>任务 1: 分析现有广播实现</name>
<files>src/Services/ConfigNotificationService.cs, src/Services/GatewayService.cs</files> <files>src/Services/ConfigNotificationService.cs, src/Services/GatewayService.cs</files>
<action> <action>
Analyze the existing implementation to understand: 分析现有实现以了解:
1. How ConfigNotificationService works (PostgreSQL NOTIFY) 1. ConfigNotificationService 如何工作PostgreSQL NOTIFY
2. How GatewayService triggers broadcasts on CRUD operations 2. GatewayService 如何在 CRUD 操作时触发广播
3. What event types and payloads are sent 3. 发送的事件类型和载荷是什么
Read the source files and document the findings. 阅读源代码并记录发现。
</action> </action>
<verify> <verify>
<automated>Files exist and contain notification logic</automated> <automated>文件存在且包含通知逻辑</automated>
</verify> </verify>
<done>Implementation analysis complete, findings documented</done> <done>实现分析完成,发现已记录</done>
</task> </task>
<task type="auto"> <task type="auto">
<name>Task 2: Map route -> service -> downstream flow</name> <name>任务 2: 绘制路由 -> 服务 -> 下游流程</name>
<files></files> <files></files>
<action> <action>
Document the complete configuration chain: 文档化完整配置链路:
1. How routes are defined in Console 1. 路由如何在 Console 中定义
2. How routes map to services 2. 路由如何映射到服务
3. How services are discovered by downstream Gateway 3. 下游 Gateway 如何发现服务
4. When config changes, how the broadcast reaches downstream 4. 配置变更时,广播如何到达下游
Reference existing code in src/Models/, src/Services/, src/Controllers/ 参考 src/Models/、src/Services/、src/Controllers/ 中的现有代码
</action> </action>
<verify> <verify>
<automated>Flow documentation created</automated> <automated>流程文档已创建</automated>
</verify> </verify>
<done>Configuration chain documented</done> <done>配置链路已文档化</done>
</task> </task>
<task type="auto"> <task type="auto">
<name>Task 3: Verify broadcast events work end-to-end</name> <name>任务 3: 验证广播端到端工作</name>
<files></files> <files></files>
<action> <action>
Verify the broadcast mechanism: 验证广播机制:
1. Check if PostgreSQL LISTEN/NOTIFY is properly configured 1. 检查 PostgreSQL LISTEN/NOTIFY 是否正确配置
2. Verify ReloadGatewayAsync sends the correct event 2. 验证 ReloadGatewayAsync 发送正确事件
3. Confirm all CRUD operations (service/route/instance) trigger broadcasts 3. 确认所有 CRUD 操作(服务/路由/实例)都触发广播
4. Test end-to-end flow if possible 4. 如可能,测试端到端流程
</action> </action>
<verify> <verify>
<automated>Build succeeds, API endpoints functional</automated> <automated>编译成功API 端点可用</automated>
</verify> </verify>
<done>Broadcast verification complete</done> <done>广播验证完成</done>
</task> </task>
</tasks> </tasks>
<verification> <verification>
1. Read and analyze ConfigNotificationService.cs 1. 阅读并分析 ConfigNotificationService.cs
2. Read and analyze GatewayService.cs 2. 阅读并分析 GatewayService.cs
3. Document route -> service -> downstream flow 3. 文档化路由 -> 服务 -> 下游流程
4. Verify build passes 4. 验证编译通过
</verification> </verification>
<success_criteria> <success_criteria>
- [x] Existing broadcast implementation analyzed - [x] 现有广播实现已分析
- [x] Configuration chain documented - [x] 配置链路已文档化
- [x] Broadcast events verified - [x] 广播事件已验证
- [x] Summary created - [x] 摘要已创建
</success_criteria> </success_criteria>
<output> <output>
After completion, create `.planning/phases/03-gateway-config-broadcast/03-SUMMARY.md` 完成后创建 `.planning/phases/03-gateway-config-broadcast/03-SUMMARY.md`
</output> </output>

View File

@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- Microsoft Packages --> <!-- Microsoft Packages -->
<PackageVersion Include="Fengling.Platform.Infrastructure" Version="1.0.11" /> <PackageVersion Include="Fengling.Platform.Infrastructure" Version="1.0.12" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" /> <PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" /> <PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" /> <PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" />

View File

@ -0,0 +1,133 @@
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Npgsql;
using Fengling.Console.Data;
using Microsoft.EntityFrameworkCore;
namespace Fengling.Console.Services;
/// <summary>
/// 配置变更通知服务接口
/// </summary>
public interface INotificationService
{
/// <summary>
/// 发布通知到指定通道
/// </summary>
Task PublishAsync(string channel, string payload, CancellationToken cancellationToken = default);
/// <summary>
/// 发布配置变更事件
/// </summary>
Task PublishConfigChangeAsync(
string eventType,
string action,
object? details = null,
CancellationToken cancellationToken = default);
}
/// <summary>
/// 配置变更事件数据
/// </summary>
public class ConfigChangeEvent
{
public string EventType { get; set; } = ""; // service, route, instance, gateway
public string Action { get; set; } = ""; // create, update, delete, reload
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
public object? Details { get; set; }
}
/// <summary>
/// PostgreSQL 通知服务实现
/// 使用 PostgreSQL NOTIFY/LISTEN 机制广播配置变更
/// </summary>
public class PgSqlNotificationService : INotificationService
{
private readonly ILogger<PgSqlNotificationService> _logger;
private readonly string _connectionString;
public const string GatewayConfigChangedChannel = "gateway_config_changed";
public PgSqlNotificationService(DbContextOptions<ConsoleDbContext> dbContextOptions, ILogger<PgSqlNotificationService> logger)
{
_logger = logger;
// 从 DbContextOptions 获取连接字符串
string? connectionString = null;
foreach (var ext in dbContextOptions.Extensions)
{
var extType = ext.GetType();
if (extType.Name.Contains("Npgsql"))
{
var prop = extType.GetProperty("ConnectionString");
if (prop != null && prop.PropertyType == typeof(string))
{
connectionString = prop.GetValue(ext) as string;
break;
}
}
}
_connectionString = connectionString
?? throw new InvalidOperationException("DefaultConnection not configured");
}
/// <inheritdoc/>
public async Task PublishAsync(string channel, string payload, CancellationToken cancellationToken = default)
{
try
{
await using var connection = new NpgsqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var cmd = new NpgsqlCommand(
$"SELECT pg_notify(@channel, @payload)",
connection);
cmd.Parameters.AddWithValue("channel", channel);
cmd.Parameters.AddWithValue("payload", payload);
await cmd.ExecuteNonQueryAsync(cancellationToken);
_logger.LogInformation("Published notification to channel '{Channel}': {Payload}", channel, payload);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to publish notification to channel '{Channel}'", channel);
}
}
/// <summary>
/// 创建配置变更事件并发布
/// </summary>
public async Task PublishConfigChangeAsync(
string eventType,
string action,
object? details = null,
CancellationToken cancellationToken = default)
{
var configEvent = new ConfigChangeEvent
{
EventType = eventType,
Action = action,
Timestamp = DateTime.UtcNow,
Details = details
};
var payload = JsonSerializer.Serialize(configEvent);
await PublishAsync(GatewayConfigChangedChannel, payload, cancellationToken);
}
}
/// <summary>
/// 通知服务扩展方法
/// </summary>
public static class NotificationServiceExtensions
{
public static IServiceCollection AddNotificationService(this IServiceCollection services)
{
services.AddScoped<INotificationService, PgSqlNotificationService>();
return services;
}
}