fromozuzhouzzz
Deploy grok2api v3.0.11 to HF Spaces
f1dd159
Raw
History Blame Contribute Delete
8.48 kB
package repository
import (
"context"
"strconv"
"time"
"github.com/chenyme/grok2api/backend/internal/domain/account"
)
// AccountConcurrencyKey 返回账号推理租约使用的统一运行态键。
// 账号维护任务必须复用该键判断是否仍有请求占用,避免复制协议字符串后发生漂移。
func AccountConcurrencyKey(accountID uint64) string {
return "account:" + strconv.FormatUint(accountID, 10)
}
// RateLimiter 定义客户端 RPM 限制边界。
type RateLimiter interface {
Allow(ctx context.Context, key string, limit int, now time.Time) (bool, error)
}
// ConcurrencyLimiter 定义客户端和账号并发租约边界。
type ConcurrencyLimiter interface {
Acquire(ctx context.Context, key string, limit int) (release func(), acquired bool, err error)
Current(ctx context.Context, key string) (int, error)
}
// ConcurrencySnapshotReader 批量读取并发租约快照;调度器会优先使用它减少远程运行态往返。
type ConcurrencySnapshotReader interface {
CurrentMany(ctx context.Context, keys []string) (map[string]int, error)
}
// StickySessionRepository 定义有过期时间的会话账号粘滞状态。
type StickySessionRepository interface {
Get(ctx context.Context, affinityKey string, now time.Time) (uint64, bool, error)
// Bind 原子保留已有有效绑定并刷新有效期;仅在绑定不存在或已过期时采用 proposedAccountID。
Bind(ctx context.Context, affinityKey string, proposedAccountID uint64, now, expiresAt time.Time) (accountID uint64, err error)
// Set 强制替换绑定,仅用于原账号已经确定不再适合当前请求时重新绑定。
Set(ctx context.Context, affinityKey string, accountID uint64, expiresAt time.Time) error
DeleteByAccount(ctx context.Context, accountID uint64) error
}
// StickySessionBatchDeleter removes bindings for many accounts using bounded remote
// batches or a single in-memory scan.
type StickySessionBatchDeleter interface {
DeleteByAccounts(ctx context.Context, accountIDs []uint64) error
}
// ReasoningReplayRepository 保存无状态多轮所需的上一轮可回放 output items。
// key 边界为 model + sessionKey;sessionKey 应使用已隔离的 PromptCacheKey。
type ReasoningReplayRepository interface {
Get(ctx context.Context, model, sessionKey string, now time.Time, ttl time.Duration) (items [][]byte, ok bool, err error)
Set(ctx context.Context, model, sessionKey string, items [][]byte, expiresAt time.Time) error
Delete(ctx context.Context, model, sessionKey string) error
}
// ObservedModelState is the latest model signal shared by runtime instances.
type ObservedModelState struct {
Model string
ObservedAt time.Time
}
// ObservedModelStateRepository coordinates duplicate model observations across instances.
// Implementations must treat this state as an optimization; the account database remains authoritative.
type ObservedModelStateRepository interface {
GetObservedModelState(ctx context.Context, accountID uint64) (ObservedModelState, bool, error)
SetObservedModelState(ctx context.Context, accountID uint64, value ObservedModelState, ttl time.Duration) error
}
// DeviceSessionRepository 定义短期 Device OAuth 会话状态。
type DeviceSessionRepository interface {
Create(ctx context.Context, value account.DeviceSession) error
Get(ctx context.Context, id string, now time.Time) (account.DeviceSession, error)
Update(ctx context.Context, value account.DeviceSession) error
Delete(ctx context.Context, id string) error
}
// DistributedLock 定义跨实例的短期互斥租约,用于避免同一账号维护任务被并发执行。
type DistributedLock interface {
Acquire(ctx context.Context, key string, ttl time.Duration) (release func(), acquired bool, err error)
}
// SettingsChangeBus 在多实例之间传递运行设置已变更的通知,设置内容仍以数据库为准。
type SettingsChangeBus interface {
PublishSettingsChanged(ctx context.Context) error
ListenSettingsChanges(ctx context.Context, handler func(context.Context) error) error
}
type InvalidationKind string
const (
InvalidationRouteChanged InvalidationKind = "route_changed"
InvalidationModelBindingChanged InvalidationKind = "model_binding_changed"
InvalidationAccountStateChanged InvalidationKind = "account_state_changed"
InvalidationAccountCredentialChanged InvalidationKind = "account_credential_changed"
InvalidationAccountCapabilityChanged InvalidationKind = "account_capability_changed"
InvalidationAccountBillingChanged InvalidationKind = "account_billing_changed"
InvalidationAccountQuotaChanged InvalidationKind = "account_quota_changed"
InvalidationAccountRecoveryChanged InvalidationKind = "account_recovery_changed"
InvalidationAccountModelQuotaChanged InvalidationKind = "account_model_quota_changed"
InvalidationClientKeyChanged InvalidationKind = "client_key_changed"
)
type InvalidationLayer string
const (
InvalidationLayerRoute InvalidationLayer = "route"
InvalidationLayerBase InvalidationLayer = "account_base"
InvalidationLayerOverlay InvalidationLayer = "account_overlay"
InvalidationLayerClientKey InvalidationLayer = "client_key"
)
type InvalidationEvent struct {
Kind InvalidationKind `json:"kind"`
Provider account.Provider `json:"provider,omitempty"`
AccountID uint64 `json:"accountId,omitempty"`
ClientKeyID uint64 `json:"clientKeyId,omitempty"`
UpstreamModel string `json:"upstreamModel,omitempty"`
Revision uint64 `json:"revision,omitempty"`
SourceInstance string `json:"sourceInstance,omitempty"`
PublishedAt time.Time `json:"publishedAt,omitempty"`
}
func (e InvalidationEvent) Layer() InvalidationLayer {
switch e.Kind {
case InvalidationRouteChanged:
return InvalidationLayerRoute
case InvalidationModelBindingChanged, InvalidationAccountCapabilityChanged, InvalidationAccountModelQuotaChanged:
return InvalidationLayerOverlay
case InvalidationAccountStateChanged, InvalidationAccountCredentialChanged, InvalidationAccountBillingChanged, InvalidationAccountQuotaChanged, InvalidationAccountRecoveryChanged:
return InvalidationLayerBase
case InvalidationClientKeyChanged:
return InvalidationLayerClientKey
default:
return ""
}
}
func (e InvalidationEvent) Valid() bool {
layer := e.Layer()
if layer == "" {
return false
}
if layer == InvalidationLayerClientKey {
return e.Provider == "" && e.AccountID == 0 && e.UpstreamModel == ""
}
switch e.Provider {
case "", account.ProviderBuild, account.ProviderWeb, account.ProviderConsole:
return true
default:
return false
}
}
type InvalidationObserver func(context.Context, InvalidationEvent)
// InvalidationBus distributes cache invalidation metadata only. Authoritative
// account, route, credential, quota, and billing data remain in the database.
type InvalidationBus interface {
PublishInvalidation(ctx context.Context, event InvalidationEvent) error
ListenInvalidations(ctx context.Context, handler func(context.Context, InvalidationEvent) error) error
}
// QuotaRecoveryQueue 保存分模式额度的到期探测事件,支持多实例原子认领。
type QuotaRecoveryQueue interface {
ScheduleQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error
EnsureQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error
ClaimDueQuotaRecoveries(ctx context.Context, now time.Time, limit int, lease time.Duration) ([]account.QuotaRecoveryEvent, error)
AckQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error
RescheduleQuotaRecovery(ctx context.Context, value account.QuotaRecoveryEvent) error
}
type QuotaRefreshDirty struct {
AccountID uint64
Mode string
Generation uint64
}
// QuotaRefreshCoordinator preserves successful-request refresh signals across
// local queue pressure and coordinates trailing refreshes between instances.
type QuotaRefreshCoordinator interface {
MarkQuotaRefreshDirty(ctx context.Context, accountID uint64, mode string, ttl time.Duration) (uint64, error)
QuotaRefreshGeneration(ctx context.Context, accountID uint64, mode string) (generation uint64, dirty bool, err error)
ClearQuotaRefreshDirty(ctx context.Context, accountID uint64, mode string, generation uint64) (bool, error)
ListQuotaRefreshDirty(ctx context.Context, now time.Time, limit int) ([]QuotaRefreshDirty, error)
}