refactor(core): align with cordis spatiotemporal composability architecture

- Purify core micro-kernel by removing context hardcoded helpers and reverse dependencies
- Eliminate init() side effects in infra plugins with reversible lifecycle disposal
- Completely isolate plugins by removing cross-plugin imports and using core/contracts
- Introduce TaskService and RiskControlService contracts for unified cross-plugin APIs
- Regenerate Swagger documentation and update developer guide matrix
- Achieve 0 violations in check_cordis_architecture.sh and 100% test pass
This commit is contained in:
ryan
2026-08-28 15:05:31 +08:00
parent fc7fae7b0e
commit 299ac30ee4
150 changed files with 4328 additions and 2923 deletions
+14 -2
View File
@@ -11,11 +11,12 @@ import (
"sync"
"time"
"github.com/redis/go-redis/v9"
"Wavelet/core"
"Wavelet/core/contracts"
"Wavelet/pkg/cache/ram"
"Wavelet/pkg/util"
"github.com/redis/go-redis/v9"
)
const (
@@ -80,7 +81,13 @@ func (p *Plugin) Name() string {
// Apply mounts the multi-layer cache service into the Context.
func (p *Plugin) Apply(ctx *core.Context) error {
redisClient := p.redisClient
if redisClient == nil {
if redisClient == nil && Redis == nil {
var err error
redisClient, err = InitRedis()
if err != nil {
return err
}
} else if redisClient == nil {
redisClient = Redis
}
@@ -103,6 +110,11 @@ func (p *Plugin) Apply(ctx *core.Context) error {
svc.startPubSubListener()
ctx.OnDispose(func() error {
svc.stopPubSubListener()
if p.redisClient == nil {
if closeErr := redisClient.Close(); closeErr != nil && !errors.Is(closeErr, redis.ErrClosed) {
return closeErr
}
}
return nil
})
}
+24 -14
View File
@@ -11,11 +11,12 @@ import (
"strings"
"time"
"Wavelet/pkg/config"
"github.com/redis/go-redis/extra/redisotel/v9"
"github.com/redis/go-redis/v9"
"github.com/redis/go-redis/v9/maintnotifications"
"go.opentelemetry.io/otel/attribute"
"Wavelet/pkg/config"
)
var (
@@ -23,17 +24,20 @@ var (
Redis redis.UniversalClient
)
func init() {
// InitRedis 初始化全局/默认 Redis 客户端实例
func InitRedis() (redis.UniversalClient, error) {
cfg := config.Config.Redis
if !cfg.Enabled {
log.Println("[Redis] is disabled, skipping Redis initialization")
return
return nil, nil
}
var client redis.UniversalClient
if cfg.ClusterMode {
// Cluster 模式
Redis = redis.NewClusterClient(&redis.ClusterOptions{
client = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: cfg.Addrs,
Username: cfg.Username,
Password: cfg.Password,
@@ -67,34 +71,40 @@ func init() {
MaintNotificationsConfig: redisMaintNotificationsConfig(cfg.MaintNotifications),
}
if cfg.MasterName != "" {
client := redis.NewFailoverClient(options.Failover())
// FailoverOptions 暂不暴露该配置,在首次建连前写入客户端选项。
client.Options().MaintNotificationsConfig = redisMaintNotificationsConfig(cfg.MaintNotifications)
Redis = client
failoverClient := redis.NewFailoverClient(options.Failover())
failoverClient.Options().MaintNotificationsConfig = redisMaintNotificationsConfig(cfg.MaintNotifications)
client = failoverClient
log.Println("[Redis] initialized in Sentinel mode")
} else {
Redis = redis.NewUniversalClient(options)
client = redis.NewUniversalClient(options)
log.Println("[Redis] initialized in Standalone mode")
}
}
// OpenTelemetry 追踪(UniversalClient 兼容)
if err := redisotel.InstrumentTracing(
Redis,
client,
redisotel.WithAttributes(
attribute.String("db.instance", fmt.Sprintf("%v", cfg.DB)),
attribute.String("db.ip", strings.Join(cfg.Addrs, ",")),
attribute.String("db.system", "Redis"),
),
); err != nil {
log.Fatalf("[Redis] failed to init trace: %v\n", err)
return nil, fmt.Errorf("redis: init trace: %w", err)
}
// 测试连接
_, err := Redis.Ping(context.Background()).Result()
if err != nil {
log.Fatalf("[Redis] failed to connect to redis: %v\n", err)
if err := client.Ping(context.Background()).Err(); err != nil {
return nil, fmt.Errorf("redis: ping: %w", err)
}
Redis = client
return client, nil
}
// SetRedisClient 设置包级 Redis 客户端(主要用于测试)
func SetRedisClient(client redis.UniversalClient) {
Redis = client
}
func redisMaintNotificationsConfig(enabled bool) *maintnotifications.Config {