mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-06 00:48:36 +00:00
Revert "feat(429): add configurable cooldown and retry strategies"
This reverts commit 6c3edc0956.
This commit is contained in:
1 parent
6c3edc0956
commit
e62ec2c42f
12 files changed
+555
-693
No files matched your search
@@ -112,23 +112,15 @@ func (h *SettingHandler) GetRateLimit429CooldownSettings(c *gin.Context) {
|
||||
}
|
||||
|
||||
response.Success(c, dto.RateLimit429CooldownSettings{
|
||||
Enabled: settings.Enabled,
|
||||
CooldownSeconds: settings.CooldownSeconds,
|
||||
Strategy: settings.Strategy,
|
||||
RetryIntervalMs: settings.RetryIntervalMs,
|
||||
RetryMaxDurationSeconds: settings.RetryMaxDurationSeconds,
|
||||
MaxAccountSwitches: settings.MaxAccountSwitches,
|
||||
Enabled: settings.Enabled,
|
||||
CooldownSeconds: settings.CooldownSeconds,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateRateLimit429CooldownSettingsRequest 更新429默认回避配置请求
|
||||
type UpdateRateLimit429CooldownSettingsRequest struct {
|
||||
Strategy string `json:"strategy"`
|
||||
RetryIntervalMs int `json:"retry_interval_ms"`
|
||||
RetryMaxDurationSeconds int `json:"retry_max_duration_seconds"`
|
||||
MaxAccountSwitches int `json:"max_account_switches"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CooldownSeconds int `json:"cooldown_seconds"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CooldownSeconds int `json:"cooldown_seconds"`
|
||||
}
|
||||
|
||||
// UpdateRateLimit429CooldownSettings 更新429默认回避配置
|
||||
@@ -141,12 +133,8 @@ func (h *SettingHandler) UpdateRateLimit429CooldownSettings(c *gin.Context) {
|
||||
}
|
||||
|
||||
settings := &service.RateLimit429CooldownSettings{
|
||||
Strategy: req.Strategy,
|
||||
RetryIntervalMs: req.RetryIntervalMs,
|
||||
RetryMaxDurationSeconds: req.RetryMaxDurationSeconds,
|
||||
MaxAccountSwitches: req.MaxAccountSwitches,
|
||||
Enabled: req.Enabled,
|
||||
CooldownSeconds: req.CooldownSeconds,
|
||||
Enabled: req.Enabled,
|
||||
CooldownSeconds: req.CooldownSeconds,
|
||||
}
|
||||
|
||||
if err := h.settingService.SetRateLimit429CooldownSettings(c.Request.Context(), settings); err != nil {
|
||||
@@ -161,12 +149,8 @@ func (h *SettingHandler) UpdateRateLimit429CooldownSettings(c *gin.Context) {
|
||||
}
|
||||
|
||||
response.Success(c, dto.RateLimit429CooldownSettings{
|
||||
Enabled: updatedSettings.Enabled,
|
||||
CooldownSeconds: updatedSettings.CooldownSeconds,
|
||||
Strategy: updatedSettings.Strategy,
|
||||
RetryIntervalMs: updatedSettings.RetryIntervalMs,
|
||||
RetryMaxDurationSeconds: updatedSettings.RetryMaxDurationSeconds,
|
||||
MaxAccountSwitches: updatedSettings.MaxAccountSwitches,
|
||||
Enabled: updatedSettings.Enabled,
|
||||
CooldownSeconds: updatedSettings.CooldownSeconds,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -148,23 +148,21 @@ type SystemSettings struct {
|
||||
GoogleOAuthRedirectURL string `json:"google_oauth_redirect_url"`
|
||||
GoogleOAuthFrontendRedirectURL string `json:"google_oauth_frontend_redirect_url"`
|
||||
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
SupportQRCodes []service.SupportQRCodeEntry `json:"support_qr_codes"`
|
||||
DownloadToolsURL string `json:"download_tools_url"`
|
||||
DocURL string `json:"doc_url"`
|
||||
HomeContent string `json:"home_content"`
|
||||
CompactHomeEnabled bool `json:"compact_home_enabled"`
|
||||
HideCcsImportButton bool `json:"hide_ccs_import_button"`
|
||||
PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"`
|
||||
PurchaseSubscriptionURL string `json:"purchase_subscription_url"`
|
||||
TableDefaultPageSize int `json:"table_default_page_size"`
|
||||
TablePageSizeOptions []int `json:"table_page_size_options"`
|
||||
CustomMenuItems []CustomMenuItem `json:"custom_menu_items"`
|
||||
CustomEndpoints []CustomEndpoint `json:"custom_endpoints"`
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
DocURL string `json:"doc_url"`
|
||||
HomeContent string `json:"home_content"`
|
||||
CompactHomeEnabled bool `json:"compact_home_enabled"`
|
||||
HideCcsImportButton bool `json:"hide_ccs_import_button"`
|
||||
PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"`
|
||||
PurchaseSubscriptionURL string `json:"purchase_subscription_url"`
|
||||
TableDefaultPageSize int `json:"table_default_page_size"`
|
||||
TablePageSizeOptions []int `json:"table_page_size_options"`
|
||||
CustomMenuItems []CustomMenuItem `json:"custom_menu_items"`
|
||||
CustomEndpoints []CustomEndpoint `json:"custom_endpoints"`
|
||||
|
||||
DefaultConcurrency int `json:"default_concurrency"`
|
||||
DefaultBalance float64 `json:"default_balance"`
|
||||
@@ -172,9 +170,6 @@ type SystemSettings struct {
|
||||
AffiliateRebateFreezeHours int `json:"affiliate_rebate_freeze_hours"`
|
||||
AffiliateRebateDurationDays int `json:"affiliate_rebate_duration_days"`
|
||||
AffiliateRebatePerInviteeCap float64 `json:"affiliate_rebate_per_invitee_cap"`
|
||||
AffiliateRebateCap float64 `json:"affiliate_rebate_cap"`
|
||||
AffiliateRebateInviteeLimit int `json:"affiliate_rebate_invitee_limit"`
|
||||
AffiliateSignupBonus float64 `json:"affiliate_signup_bonus"`
|
||||
AdminRechargeRebateEnabled bool `json:"affiliate_admin_recharge_enabled"`
|
||||
DefaultUserRPMLimit int `json:"default_user_rpm_limit"`
|
||||
DefaultSubscriptions []DefaultSubscriptionSetting `json:"default_subscriptions"`
|
||||
@@ -310,23 +305,13 @@ type SystemSettings struct {
|
||||
ChannelMonitorMode string `json:"channel_monitor_mode"`
|
||||
ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"`
|
||||
ChannelMonitorHideThroughput bool `json:"channel_monitor_hide_throughput"`
|
||||
ChannelMonitorShowQuota bool `json:"channel_monitor_show_quota"`
|
||||
|
||||
// Grok model mapping policy (admin settings; empty account mapping falls back to these).
|
||||
GrokDefaultTextModel string `json:"grok_default_text_model"`
|
||||
GrokCrossClientModelMapEnabled bool `json:"grok_cross_client_model_map_enabled"`
|
||||
GrokDefaultBaseURLMode string `json:"grok_default_base_url_mode"`
|
||||
|
||||
// Kiro runtime defaults (admin-only; not exposed on PublicSettings).
|
||||
KiroDefaultVersion string `json:"kiro_version"`
|
||||
KiroDefaultCommit string `json:"kiro_commit"`
|
||||
KiroDefaultSystemVersion string `json:"system_version"`
|
||||
KiroDefaultNodeVersion string `json:"node_version"`
|
||||
KiroCacheHitRateScale int `json:"cache_hit_rate_scale"`
|
||||
KiroCacheMinBlockTokens int `json:"cache_min_block_tokens"`
|
||||
KiroCacheIndependentTTLSeconds int `json:"cache_independent_ttl_seconds"`
|
||||
KiroCachePrefixTTLSeconds int `json:"cache_prefix_ttl_seconds"`
|
||||
KiroCodeExecutionSandboxCommand string `json:"kiro_code_execution_sandbox_command"`
|
||||
|
||||
// Available Channels feature switch (user-facing aggregate view)
|
||||
AvailableChannelsEnabled bool `json:"available_channels_enabled"`
|
||||
|
||||
@@ -345,14 +330,6 @@ type SystemSettings struct {
|
||||
// Affiliate (邀请返利) feature switch
|
||||
AffiliateEnabled bool `json:"affiliate_enabled"`
|
||||
|
||||
// Ticket feature switch (default enabled)
|
||||
TicketEnabled bool `json:"ticket_enabled"`
|
||||
|
||||
IPMultiAccountBanEnabled bool `json:"ip_multi_account_ban_enabled"`
|
||||
IPMultiAccountBanWindowMinutes int `json:"ip_multi_account_ban_window_minutes"`
|
||||
IPMultiAccountBanThreshold int `json:"ip_multi_account_ban_threshold"`
|
||||
IPMultiAccountBanLearningUntil string `json:"ip_multi_account_ban_learning_until"`
|
||||
|
||||
// OpenAI fast/flex policy
|
||||
OpenAIFastPolicySettings *OpenAIFastPolicySettings `json:"openai_fast_policy_settings,omitempty"`
|
||||
|
||||
@@ -372,61 +349,58 @@ type DefaultSubscriptionSetting struct {
|
||||
}
|
||||
|
||||
type PublicSettings struct {
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
EmailVerifyEnabled bool `json:"email_verify_enabled"`
|
||||
ForceEmailOnThirdPartySignup bool `json:"force_email_on_third_party_signup"`
|
||||
RegistrationEmailSuffixWhitelist []string `json:"registration_email_suffix_whitelist"`
|
||||
RegistrationEmailDomainQuotaEnabled bool `json:"registration_email_domain_quota_enabled"`
|
||||
PromoCodeEnabled bool `json:"promo_code_enabled"`
|
||||
PasswordResetEnabled bool `json:"password_reset_enabled"`
|
||||
InvitationCodeEnabled bool `json:"invitation_code_enabled"`
|
||||
TotpEnabled bool `json:"totp_enabled"` // TOTP 双因素认证
|
||||
PasskeyEnabled bool `json:"passkey_enabled"`
|
||||
LoginAgreementEnabled bool `json:"login_agreement_enabled"`
|
||||
LoginAgreementMode string `json:"login_agreement_mode"`
|
||||
LoginAgreementUpdatedAt string `json:"login_agreement_updated_at"`
|
||||
LoginAgreementRevision string `json:"login_agreement_revision"`
|
||||
LoginAgreementDocuments []LoginAgreementDocument `json:"login_agreement_documents"`
|
||||
TurnstileEnabled bool `json:"turnstile_enabled"`
|
||||
TurnstileSiteKey string `json:"turnstile_site_key"`
|
||||
TencentCaptchaEnabled bool `json:"tencent_captcha_enabled"`
|
||||
TencentCaptchaAppID string `json:"tencent_captcha_app_id"`
|
||||
TencentCaptchaRegion string `json:"tencent_captcha_region"`
|
||||
AliyunCaptchaEnabled bool `json:"aliyun_captcha_enabled"`
|
||||
AliyunCaptchaSceneID string `json:"aliyun_captcha_scene_id"`
|
||||
AliyunCaptchaPrefix string `json:"aliyun_captcha_prefix"`
|
||||
AliyunCaptchaRegion string `json:"aliyun_captcha_region"`
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
SupportQRCodes []service.SupportQRCodeEntry `json:"support_qr_codes"`
|
||||
DownloadToolsURL string `json:"download_tools_url"`
|
||||
DocURL string `json:"doc_url"`
|
||||
HomeContent string `json:"home_content"`
|
||||
CompactHomeEnabled bool `json:"compact_home_enabled"`
|
||||
HideCcsImportButton bool `json:"hide_ccs_import_button"`
|
||||
PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"`
|
||||
PurchaseSubscriptionURL string `json:"purchase_subscription_url"`
|
||||
TableDefaultPageSize int `json:"table_default_page_size"`
|
||||
TablePageSizeOptions []int `json:"table_page_size_options"`
|
||||
CustomMenuItems []CustomMenuItem `json:"custom_menu_items"`
|
||||
CustomEndpoints []CustomEndpoint `json:"custom_endpoints"`
|
||||
DingTalkOAuthEnabled bool `json:"dingtalk_oauth_enabled"`
|
||||
LinuxDoOAuthEnabled bool `json:"linuxdo_oauth_enabled"`
|
||||
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
||||
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
||||
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
||||
WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"`
|
||||
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
||||
OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"`
|
||||
GitHubOAuthEnabled bool `json:"github_oauth_enabled"`
|
||||
GoogleOAuthEnabled bool `json:"google_oauth_enabled"`
|
||||
SoraClientEnabled bool `json:"sora_client_enabled"`
|
||||
BackendModeEnabled bool `json:"backend_mode_enabled"`
|
||||
PaymentEnabled bool `json:"payment_enabled"`
|
||||
Version string `json:"version"`
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
EmailVerifyEnabled bool `json:"email_verify_enabled"`
|
||||
ForceEmailOnThirdPartySignup bool `json:"force_email_on_third_party_signup"`
|
||||
RegistrationEmailSuffixWhitelist []string `json:"registration_email_suffix_whitelist"`
|
||||
RegistrationEmailDomainQuotaEnabled bool `json:"registration_email_domain_quota_enabled"`
|
||||
PromoCodeEnabled bool `json:"promo_code_enabled"`
|
||||
PasswordResetEnabled bool `json:"password_reset_enabled"`
|
||||
InvitationCodeEnabled bool `json:"invitation_code_enabled"`
|
||||
TotpEnabled bool `json:"totp_enabled"` // TOTP 双因素认证
|
||||
PasskeyEnabled bool `json:"passkey_enabled"`
|
||||
LoginAgreementEnabled bool `json:"login_agreement_enabled"`
|
||||
LoginAgreementMode string `json:"login_agreement_mode"`
|
||||
LoginAgreementUpdatedAt string `json:"login_agreement_updated_at"`
|
||||
LoginAgreementRevision string `json:"login_agreement_revision"`
|
||||
LoginAgreementDocuments []LoginAgreementDocument `json:"login_agreement_documents"`
|
||||
TurnstileEnabled bool `json:"turnstile_enabled"`
|
||||
TurnstileSiteKey string `json:"turnstile_site_key"`
|
||||
TencentCaptchaEnabled bool `json:"tencent_captcha_enabled"`
|
||||
TencentCaptchaAppID string `json:"tencent_captcha_app_id"`
|
||||
TencentCaptchaRegion string `json:"tencent_captcha_region"`
|
||||
AliyunCaptchaEnabled bool `json:"aliyun_captcha_enabled"`
|
||||
AliyunCaptchaSceneID string `json:"aliyun_captcha_scene_id"`
|
||||
AliyunCaptchaPrefix string `json:"aliyun_captcha_prefix"`
|
||||
AliyunCaptchaRegion string `json:"aliyun_captcha_region"`
|
||||
SiteName string `json:"site_name"`
|
||||
SiteLogo string `json:"site_logo"`
|
||||
SiteSubtitle string `json:"site_subtitle"`
|
||||
APIBaseURL string `json:"api_base_url"`
|
||||
ContactInfo string `json:"contact_info"`
|
||||
DocURL string `json:"doc_url"`
|
||||
HomeContent string `json:"home_content"`
|
||||
CompactHomeEnabled bool `json:"compact_home_enabled"`
|
||||
HideCcsImportButton bool `json:"hide_ccs_import_button"`
|
||||
PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"`
|
||||
PurchaseSubscriptionURL string `json:"purchase_subscription_url"`
|
||||
TableDefaultPageSize int `json:"table_default_page_size"`
|
||||
TablePageSizeOptions []int `json:"table_page_size_options"`
|
||||
CustomMenuItems []CustomMenuItem `json:"custom_menu_items"`
|
||||
CustomEndpoints []CustomEndpoint `json:"custom_endpoints"`
|
||||
DingTalkOAuthEnabled bool `json:"dingtalk_oauth_enabled"`
|
||||
LinuxDoOAuthEnabled bool `json:"linuxdo_oauth_enabled"`
|
||||
WeChatOAuthEnabled bool `json:"wechat_oauth_enabled"`
|
||||
WeChatOAuthOpenEnabled bool `json:"wechat_oauth_open_enabled"`
|
||||
WeChatOAuthMPEnabled bool `json:"wechat_oauth_mp_enabled"`
|
||||
WeChatOAuthMobileEnabled bool `json:"wechat_oauth_mobile_enabled"`
|
||||
OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"`
|
||||
OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"`
|
||||
GitHubOAuthEnabled bool `json:"github_oauth_enabled"`
|
||||
GoogleOAuthEnabled bool `json:"google_oauth_enabled"`
|
||||
BackendModeEnabled bool `json:"backend_mode_enabled"`
|
||||
PaymentEnabled bool `json:"payment_enabled"`
|
||||
Version string `json:"version"`
|
||||
// 服务器全局时区(IANA 名称与当前 UTC 偏移,如 "Asia/Shanghai" / "+08:00")。
|
||||
// 高峰时段等按服务器本地时间判定的窗口,前端展示时据此标注,避免用户按浏览器本地时间误读。
|
||||
ServerTimezone string `json:"server_timezone"`
|
||||
@@ -440,6 +414,7 @@ type PublicSettings struct {
|
||||
ChannelMonitorMode string `json:"channel_monitor_mode"`
|
||||
ChannelMonitorDefaultIntervalSeconds int `json:"channel_monitor_default_interval_seconds"`
|
||||
ChannelMonitorHideThroughput bool `json:"channel_monitor_hide_throughput"`
|
||||
ChannelMonitorShowQuota bool `json:"channel_monitor_show_quota"`
|
||||
|
||||
AvailableChannelsEnabled bool `json:"available_channels_enabled"`
|
||||
|
||||
@@ -447,7 +422,6 @@ type PublicSettings struct {
|
||||
ModelPlazaRequireAuth bool `json:"model_plaza_require_auth"`
|
||||
|
||||
AffiliateEnabled bool `json:"affiliate_enabled"`
|
||||
TicketEnabled bool `json:"ticket_enabled"`
|
||||
|
||||
RiskControlEnabled bool `json:"risk_control_enabled"`
|
||||
|
||||
@@ -468,12 +442,8 @@ type OverloadCooldownSettings struct {
|
||||
|
||||
// RateLimit429CooldownSettings 429默认回避配置 DTO
|
||||
type RateLimit429CooldownSettings struct {
|
||||
Strategy string `json:"strategy"`
|
||||
RetryIntervalMs int `json:"retry_interval_ms"`
|
||||
RetryMaxDurationSeconds int `json:"retry_max_duration_seconds"`
|
||||
MaxAccountSwitches int `json:"max_account_switches"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CooldownSeconds int `json:"cooldown_seconds"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CooldownSeconds int `json:"cooldown_seconds"`
|
||||
}
|
||||
|
||||
// PanelRateLimitSettings 面板 API 限流配置 DTO
|
||||
|
||||
@@ -56,16 +56,13 @@ const (
|
||||
const profitVetoExhaustedMessage = "No available accounts: all candidates rejected by group profit control"
|
||||
|
||||
func sameAccountRetryDelayFor(failoverErr *service.UpstreamFailoverError, retryCount int) time.Duration {
|
||||
// An OAuth 429 with a request-scoped deadline intentionally retries
|
||||
// immediately; zero is meaningful here and must not fall back to 500ms.
|
||||
if failoverErr != nil && failoverErr.StatusCode == http.StatusTooManyRequests &&
|
||||
!failoverErr.SameAccountRetryDeadline.IsZero() && failoverErr.SameAccountRetryDelay <= 0 {
|
||||
return 0
|
||||
if failoverErr == nil {
|
||||
return sameAccountRetryDelay
|
||||
}
|
||||
if failoverErr != nil && failoverErr.SameAccountRetryDelay > 0 {
|
||||
if failoverErr.SameAccountRetryDelay > 0 {
|
||||
return failoverErr.SameAccountRetryDelay
|
||||
}
|
||||
if failoverErr == nil || !failoverErr.RequestScopedTransient || retryCount <= 1 {
|
||||
if !failoverErr.RequestScopedTransient || retryCount <= 1 {
|
||||
return sameAccountRetryDelay
|
||||
}
|
||||
|
||||
@@ -79,43 +76,10 @@ func sameAccountRetryDelayFor(failoverErr *service.UpstreamFailoverError, retryC
|
||||
return delay
|
||||
}
|
||||
|
||||
func sameAccountRetryAllowed(failoverErr *service.UpstreamFailoverError, retryCount, retryLimit int) bool {
|
||||
if failoverErr == nil || !failoverErr.RetryableOnSameAccount {
|
||||
return false
|
||||
}
|
||||
if retryLimit > 0 && retryCount >= retryLimit {
|
||||
return false
|
||||
}
|
||||
if !failoverErr.SameAccountRetryDeadline.IsZero() {
|
||||
return time.Now().Before(failoverErr.SameAccountRetryDeadline)
|
||||
}
|
||||
return retryCount < retryLimit
|
||||
}
|
||||
|
||||
func pinSameAccountRetryContext(
|
||||
ctx context.Context,
|
||||
fs *FailoverState,
|
||||
accountID int64,
|
||||
groupID *int64,
|
||||
failoverErr *service.UpstreamFailoverError,
|
||||
prevRetryCount int,
|
||||
prevSwitchCount int,
|
||||
bridgeOldKeys bool,
|
||||
) context.Context {
|
||||
if ctx == nil || fs == nil || failoverErr == nil || !failoverErr.RetryableOnSameAccount {
|
||||
return ctx
|
||||
}
|
||||
if fs.SwitchCount != prevSwitchCount {
|
||||
return ctx
|
||||
}
|
||||
if fs.SameAccountRetryCount[accountID] != prevRetryCount+1 {
|
||||
return ctx
|
||||
}
|
||||
prefetchedGroupID := int64(0)
|
||||
if groupID != nil {
|
||||
prefetchedGroupID = *groupID
|
||||
}
|
||||
return service.WithPrefetchedStickySession(ctx, accountID, prefetchedGroupID, bridgeOldKeys)
|
||||
// sameAccountRetryDeadlineAllows prevents a retry from starting after the
|
||||
// service-provided same-account retry window has elapsed.
|
||||
func sameAccountRetryDeadlineAllows(failoverErr *service.UpstreamFailoverError) bool {
|
||||
return failoverErr == nil || failoverErr.SameAccountRetryDeadline.IsZero() || time.Now().Before(failoverErr.SameAccountRetryDeadline)
|
||||
}
|
||||
|
||||
// FailoverState 跨循环迭代共享的 failover 状态
|
||||
@@ -168,24 +132,6 @@ func (s *FailoverState) RecordProfitVeto(accountID int64) FailoverAction {
|
||||
return FailoverContinue
|
||||
}
|
||||
|
||||
// RecordConcurrencyTimeout excludes a busy account after the slot ladder
|
||||
// (deadline two-shot or wait-queue full) and continues onto another account
|
||||
// while the original sticky binding is preserved by the caller.
|
||||
func (s *FailoverState) RecordConcurrencyTimeout(accountID int64) FailoverAction {
|
||||
if s == nil {
|
||||
return FailoverExhausted
|
||||
}
|
||||
if s.FailedAccountIDs == nil {
|
||||
s.FailedAccountIDs = make(map[int64]struct{})
|
||||
}
|
||||
s.FailedAccountIDs[accountID] = struct{}{}
|
||||
if s.SwitchCount >= s.MaxSwitches {
|
||||
return FailoverExhausted
|
||||
}
|
||||
s.SwitchCount++
|
||||
return FailoverContinue
|
||||
}
|
||||
|
||||
// ProfitVetoCount 返回本次请求累计的利润否决次数(供日志使用)。
|
||||
func (s *FailoverState) ProfitVetoCount() int { return s.profitVetoCount }
|
||||
|
||||
@@ -223,27 +169,27 @@ func (s *FailoverState) HandleFailoverError(
|
||||
return FailoverExhausted
|
||||
}
|
||||
|
||||
retryMax := retryLimit
|
||||
if failoverErr.SameAccountRetryMax > 0 {
|
||||
retryMax = failoverErr.SameAccountRetryMax
|
||||
}
|
||||
|
||||
// 同账号重试不算切换账号,粘性会话仅在实际切换时强制缓存计费。
|
||||
sameAccountRetry := sameAccountRetryAllowed(failoverErr, s.SameAccountRetryCount[accountID], retryMax)
|
||||
retryCount := s.SameAccountRetryCount[accountID]
|
||||
sameAccountRetryAllowed := failoverErr.RetryableOnSameAccount && retryLimit > 0 && retryCount < retryLimit
|
||||
if sameAccountRetryAllowed && !failoverErr.SameAccountRetryDeadline.IsZero() {
|
||||
sameAccountRetryAllowed = time.Now().Before(failoverErr.SameAccountRetryDeadline)
|
||||
}
|
||||
sameAccountRetry := sameAccountRetryAllowed
|
||||
if needForceCacheBilling(s.hasBoundSession, failoverErr, sameAccountRetry) {
|
||||
s.ForceCacheBilling = true
|
||||
}
|
||||
|
||||
// 同账号重试:对 RetryableOnSameAccount 的临时性错误,先在同一账号上重试。
|
||||
// 重试次数上限 retryLimit 由调用方传入(账号级 pool_mode_retry_count 配置)。
|
||||
if sameAccountRetryAllowed(failoverErr, s.SameAccountRetryCount[accountID], retryMax) {
|
||||
if sameAccountRetryAllowed {
|
||||
s.SameAccountRetryCount[accountID]++
|
||||
retryDelay := sameAccountRetryDelayFor(failoverErr, s.SameAccountRetryCount[accountID])
|
||||
logger.FromContext(ctx).Warn("gateway.failover_same_account_retry",
|
||||
zap.Int64("account_id", accountID),
|
||||
zap.Int("upstream_status", failoverErr.StatusCode),
|
||||
zap.Int("same_account_retry_count", s.SameAccountRetryCount[accountID]),
|
||||
zap.Int("same_account_retry_max", retryMax),
|
||||
zap.Int("same_account_retry_max", retryLimit),
|
||||
zap.Duration("retry_delay", retryDelay),
|
||||
)
|
||||
if !sleepWithContext(ctx, retryDelay) {
|
||||
@@ -259,11 +205,6 @@ func (s *FailoverState) HandleFailoverError(
|
||||
|
||||
// 加入失败列表
|
||||
s.FailedAccountIDs[accountID] = struct{}{}
|
||||
for _, excludedAccountID := range failoverErr.ExcludedAccountIDs {
|
||||
if excludedAccountID > 0 {
|
||||
s.FailedAccountIDs[excludedAccountID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否耗尽
|
||||
if s.SwitchCount >= s.MaxSwitches {
|
||||
|
||||
Reference in new issue
Block a user