53 lines
2.1 KiB
Go
53 lines
2.1 KiB
Go
package dispatch
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
// CatalogPort 渠道目录端口:返回某租户 + 模型的候选渠道快照(含最近健康/负载读值)。
|
|
// 实现方保证 O(1) 内存读取,禁止在调用路径中查库。
|
|
type CatalogPort interface {
|
|
Snapshot(ctx context.Context, tenantID int64, model string, scope []int64) []Channel
|
|
}
|
|
|
|
// StatePort 运行时状态端口:绑定 / 健康上报 / 探测令牌 / 容量租约 / 凭证冷却。
|
|
// 实现方保证多副本原子性(Redis Lua)。
|
|
type StatePort interface {
|
|
// 绑定(会话粘性)。失败不删绑定,只有 TTL 过期或守卫不合格触发重绑。
|
|
GetBinding(ctx context.Context, sessionKey string) (channelID int64, ok bool)
|
|
SetBinding(ctx context.Context, sessionKey string, channelID int64, ttl time.Duration)
|
|
TouchBinding(ctx context.Context, sessionKey string, ttl time.Duration)
|
|
InvalidateChannelBindings(ctx context.Context, channelID int64)
|
|
|
|
// 健康上报:fire-and-forget,实现方内部异步化。
|
|
ReportOutcome(o Outcome)
|
|
|
|
// 熔断探测令牌:HALF_OPEN 时每窗口全局只放行一个真实请求。
|
|
// model 为空串 = 渠道级熔断 key;非空 = 渠道×模型级熔断 key。
|
|
TryProbeToken(ctx context.Context, channelID int64, model string) bool
|
|
|
|
// 容量租约(多副本安全,实例崩溃后自愈)。
|
|
AcquireLease(ctx context.Context, channelID int64, softLimit int, requestID string) bool
|
|
RefreshLease(ctx context.Context, channelID int64, requestID string)
|
|
ReleaseLease(ctx context.Context, channelID int64, requestID string)
|
|
|
|
// 凭证冷却。
|
|
IsCredentialCooled(ctx context.Context, keyID int64) bool
|
|
CoolCredential(ctx context.Context, keyID int64, ttl time.Duration)
|
|
}
|
|
|
|
// Clock 时钟端口,便于测试注入假时钟。
|
|
type Clock interface {
|
|
Now() time.Time
|
|
}
|
|
|
|
// Entropy 熵源:返回 [0,1) 均匀随机数,用于退避 jitter。测试注入固定值即可复现。
|
|
type Entropy func() float64
|
|
|
|
// SystemClock 真实时钟。
|
|
type SystemClock struct{}
|
|
|
|
// Now 返回当前时间。
|
|
func (SystemClock) Now() time.Time { return time.Now() }
|