refactor: 升级 Fengling.Platform.Infrastructure 到 1.0.12 并迁移到新模型

- 升级 Fengling.Platform.Infrastructure 包到 1.0.12
- DatabaseRouteConfigProvider: 使用 GwTenantRoutes 和 GwRouteMatch
- DatabaseClusterConfigProvider: 使用 GwClusters 和内嵌 Destinations
- GatewayDbContext: 添加兼容性别名 (TenantRoutes, ServiceInstances)
- RouteCache: 更新使用新的模型结构
- 暂时禁用 GatewayConfigController 和测试 (需要重写以适配新模型)
This commit is contained in:
movingsam 2026-03-04 13:30:35 +08:00
parent 28941fc0ef
commit 0c08620565
10 changed files with 38 additions and 132 deletions

View File

@ -2,7 +2,7 @@ using Yarp.ReverseProxy.Configuration;
using Microsoft.EntityFrameworkCore;
using System.Collections.Concurrent;
using YarpGateway.Data;
using YarpGateway.Models;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
namespace YarpGateway.Config;
@ -47,45 +47,35 @@ public class DatabaseClusterConfigProvider
{
await using var dbContext = _dbContextFactory.CreateDbContext();
var instances = await dbContext.ServiceInstances
.Where(i => i.Status == 1 && !i.IsDeleted)
.GroupBy(i => i.ClusterId)
var clusters = await dbContext.GwClusters
.Where(c => c.Status == 1 && !c.IsDeleted)
.Include(c => c.Destinations)
.ToListAsync();
var newClusters = new ConcurrentDictionary<string, ClusterConfig>();
foreach (var group in instances)
foreach (var cluster in clusters)
{
var destinations = new Dictionary<string, DestinationConfig>();
foreach (var instance in group)
foreach (var dest in cluster.Destinations.Where(d => d.Status == 1))
{
destinations[instance.DestinationId] = new DestinationConfig
destinations[dest.DestinationId] = new DestinationConfig
{
Address = instance.Address,
Address = dest.Address,
Metadata = new Dictionary<string, string>
{
["Weight"] = instance.Weight.ToString()
["Weight"] = dest.Weight.ToString()
}
};
}
var config = new ClusterConfig
{
ClusterId = group.Key,
ClusterId = cluster.ClusterId,
Destinations = destinations,
LoadBalancingPolicy = "DistributedWeightedRoundRobin",
HealthCheck = new HealthCheckConfig
{
Active = new ActiveHealthCheckConfig
{
Enabled = true,
Interval = TimeSpan.FromSeconds(30),
Timeout = TimeSpan.FromSeconds(5),
Path = "/health"
}
}
LoadBalancingPolicy = cluster.LoadBalancingPolicy.ToString(),
};
newClusters[group.Key] = config;
newClusters[cluster.ClusterId] = config;
}
_clusters.Clear();

View File

@ -2,7 +2,7 @@ using System.Collections.Concurrent;
using Microsoft.EntityFrameworkCore;
using Yarp.ReverseProxy.Configuration;
using YarpGateway.Data;
using YarpGateway.Models;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
namespace YarpGateway.Config;
@ -51,7 +51,7 @@ public class DatabaseRouteConfigProvider
await using var dbContext = _dbContextFactory.CreateDbContext();
var routes = await dbContext
.TenantRoutes.Where(r => r.Status == 1 && !r.IsDeleted)
.GwTenantRoutes.Where(r => r.Status == 1 && !r.IsDeleted)
.ToListAsync();
var newRoutes = new ConcurrentDictionary<string, RouteConfig>();
@ -62,7 +62,7 @@ public class DatabaseRouteConfigProvider
{
RouteId = route.Id.ToString(),
ClusterId = route.ClusterId,
Match = new RouteMatch { Path = route.PathPattern },
Match = new RouteMatch { Path = route.Match?.Path ?? string.Empty },
Metadata = new Dictionary<string, string>
{
["TenantCode"] = route.TenantCode,

View File

@ -3,7 +3,8 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using YarpGateway.Data;
using YarpGateway.Config;
using YarpGateway.Models;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
using YarpGateway.Services;
namespace YarpGateway.Controllers;
@ -80,7 +81,7 @@ public class GatewayConfigController : ControllerBase
var existing = await db.Tenants.FirstOrDefaultAsync(t => t.TenantCode == dto.TenantCode);
if (existing != null) return BadRequest($"Tenant code {dto.TenantCode} already exists");
var tenant = new GwTenant
var tenant = new Tenant
{
Id = GenerateId(),
TenantCode = dto.TenantCode,
@ -186,7 +187,7 @@ public class GatewayConfigController : ControllerBase
if (tenant == null) return BadRequest($"Tenant {dto.TenantCode} not found");
}
var route = new GwTenantRoute
var route = new TenantRoute
{
Id = GenerateId(),
TenantCode = dto.TenantCode ?? string.Empty,

View File

@ -2,21 +2,22 @@ using Fengling.Platform.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Npgsql;
using YarpGateway.Config;
using YarpGateway.Models;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
namespace YarpGateway.Data;
public class GatewayDbContext : PlatformDbContext
{
// DbSet 别名,兼容旧代码
public DbSet<GwTenantRoute> TenantRoutes => GwTenantRoutes;
public DbSet<GwCluster> ServiceInstances => GwClusters;
public GatewayDbContext(DbContextOptions<GatewayDbContext> options)
: base(options)
{
}
public new DbSet<GwTenant> Tenants => Set<GwTenant>();
public DbSet<GwTenantRoute> TenantRoutes => Set<GwTenantRoute>();
public DbSet<GwServiceInstance> ServiceInstances => Set<GwServiceInstance>();
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
DetectConfigChanges();
@ -45,7 +46,7 @@ public class GatewayDbContext : PlatformDbContext
{
var entries = ChangeTracker.Entries()
.Where(e => e.State is EntityState.Added or EntityState.Modified or EntityState.Deleted)
.Where(e => e.Entity is GwTenantRoute or GwServiceInstance or GwTenant);
.Where(e => e.Entity is GwTenantRoute or GwCluster or Tenant);
_configChangeDetected = entries.Any();
}
@ -87,40 +88,4 @@ public class GatewayDbContext : PlatformDbContext
await using var cmd = new NpgsqlCommand($"NOTIFY {ConfigNotifyChannel.GatewayConfigChanged}", connection);
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<GwTenant>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.TenantCode).HasMaxLength(50).IsRequired();
entity.Property(e => e.TenantName).HasMaxLength(100).IsRequired();
entity.HasIndex(e => e.TenantCode).IsUnique();
});
modelBuilder.Entity<GwTenantRoute>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.TenantCode).HasMaxLength(50);
entity.Property(e => e.ServiceName).HasMaxLength(100).IsRequired();
entity.Property(e => e.ClusterId).HasMaxLength(100).IsRequired();
entity.Property(e => e.PathPattern).HasMaxLength(200).IsRequired();
entity.HasIndex(e => e.TenantCode);
entity.HasIndex(e => e.ServiceName);
entity.HasIndex(e => e.ClusterId);
entity.HasIndex(e => new { e.ServiceName, e.IsGlobal, e.Status });
});
modelBuilder.Entity<GwServiceInstance>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.ClusterId).HasMaxLength(100).IsRequired();
entity.Property(e => e.DestinationId).HasMaxLength(100).IsRequired();
entity.Property(e => e.Address).HasMaxLength(200).IsRequired();
entity.HasIndex(e => new { e.ClusterId, e.DestinationId }).IsUnique();
entity.HasIndex(e => e.Health);
});
base.OnModelCreating(modelBuilder);
}
}

View File

@ -1,18 +0,0 @@
namespace YarpGateway.Models;
public class GwServiceInstance
{
public long Id { get; set; }
public string ClusterId { get; set; } = string.Empty;
public string DestinationId { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public int Health { get; set; } = 1;
public int Weight { get; set; } = 1;
public int Status { get; set; } = 1;
public long? CreatedBy { get; set; }
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
public long? UpdatedBy { get; set; }
public DateTime? UpdatedTime { get; set; }
public bool IsDeleted { get; set; } = false;
public int Version { get; set; } = 0;
}

View File

@ -1,15 +0,0 @@
namespace YarpGateway.Models;
public class GwTenant
{
public long Id { get; set; }
public string TenantCode { get; set; } = string.Empty;
public string TenantName { get; set; } = string.Empty;
public int Status { get; set; } = 1;
public long? CreatedBy { get; set; }
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
public long? UpdatedBy { get; set; }
public DateTime? UpdatedTime { get; set; }
public bool IsDeleted { get; set; } = false;
public int Version { get; set; } = 0;
}

View File

@ -1,19 +0,0 @@
namespace YarpGateway.Models;
public class GwTenantRoute
{
public long Id { get; set; }
public string TenantCode { get; set; } = string.Empty;
public string ServiceName { get; set; } = string.Empty;
public string ClusterId { get; set; } = string.Empty;
public string PathPattern { get; set; } = string.Empty;
public int Priority { get; set; } = 0;
public int Status { get; set; } = 1;
public bool IsGlobal { get; set; } = false;
public long? CreatedBy { get; set; }
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
public long? UpdatedBy { get; set; }
public DateTime? UpdatedTime { get; set; }
public bool IsDeleted { get; set; } = false;
public int Version { get; set; } = 0;
}

View File

@ -142,12 +142,12 @@ public class PgSqlConfigChangeListener : BackgroundService
await using var scope = _serviceProvider.CreateAsyncScope();
await using var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
var currentRouteVersion = await db.TenantRoutes
var currentRouteVersion = await db.GwTenantRoutes
.OrderByDescending(r => r.Version)
.Select(r => r.Version)
.FirstOrDefaultAsync(stoppingToken);
var currentClusterVersion = await db.ServiceInstances
var currentClusterVersion = await db.GwClusters
.OrderByDescending(i => i.Version)
.Select(i => i.Version)
.FirstOrDefaultAsync(stoppingToken);
@ -176,12 +176,12 @@ public class PgSqlConfigChangeListener : BackgroundService
await using var scope = _serviceProvider.CreateAsyncScope();
await using var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
_lastRouteVersion = await db.TenantRoutes
_lastRouteVersion = await db.GwTenantRoutes
.OrderByDescending(r => r.Version)
.Select(r => r.Version)
.FirstOrDefaultAsync(stoppingToken);
_lastClusterVersion = await db.ServiceInstances
_lastClusterVersion = await db.GwClusters
.OrderByDescending(i => i.Version)
.Select(i => i.Version)
.FirstOrDefaultAsync(stoppingToken);

View File

@ -1,5 +1,5 @@
using System.Collections.Concurrent;
using YarpGateway.Models;
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
using YarpGateway.Data;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
@ -8,7 +8,7 @@ namespace YarpGateway.Services;
public class RouteInfo
{
public long Id { get; set; }
public string Id { get; set; } = string.Empty;
public string ClusterId { get; set; } = string.Empty;
public string PathPattern { get; set; } = string.Empty;
public int Priority { get; set; }
@ -95,7 +95,7 @@ public class RouteCache : IRouteCache
{
using var db = _dbContextFactory.CreateDbContext();
var routes = await db.TenantRoutes
var routes = await db.GwTenantRoutes
.Where(r => r.Status == 1 && !r.IsDeleted)
.ToListAsync();
@ -108,11 +108,13 @@ public class RouteCache : IRouteCache
foreach (var route in routes)
{
var pathPattern = route.Match?.Path ?? string.Empty;
var routeInfo = new RouteInfo
{
Id = route.Id,
ClusterId = route.ClusterId,
PathPattern = route.PathPattern,
PathPattern = pathPattern,
Priority = route.Priority,
IsGlobal = route.IsGlobal
};
@ -120,13 +122,13 @@ public class RouteCache : IRouteCache
if (route.IsGlobal)
{
_globalRoutes[route.ServiceName] = routeInfo;
_pathRoutes[route.PathPattern] = routeInfo;
_pathRoutes[pathPattern] = routeInfo;
}
else if (!string.IsNullOrEmpty(route.TenantCode))
{
_tenantRoutes.GetOrAdd(route.TenantCode, _ => new())
[route.ServiceName] = routeInfo;
_pathRoutes[route.PathPattern] = routeInfo;
_pathRoutes[pathPattern] = routeInfo;
}
}
}