account_test_admission.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package service
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. )
  8. var ErrIntelligentAccountBusy = errors.New("账号业务并发已满,测试等待空闲容量")
  9. type TestAdmissionWaitError struct {
  10. Until time.Time
  11. Reason string
  12. }
  13. func (e *TestAdmissionWaitError) Error() string { return e.Reason }
  14. func (e *TestAdmissionWaitError) Unwrap() error { return ErrIntelligentAccountBusy }
  15. // Account/model cooldowns apply to probes too. This never changes policy or
  16. // clears limits; it merely delays an attempt until the latest known boundary.
  17. func accountTestCooldown(ctx context.Context, a *Account, model string, now time.Time) error {
  18. if a == nil {
  19. return errors.New("账号不存在")
  20. }
  21. until, reason := now, ""
  22. for _, item := range []struct {
  23. deadline *time.Time
  24. reason string
  25. }{
  26. {a.RateLimitResetAt, "账号限流冷却尚未结束"}, {a.OverloadUntil, "账号过载冷却尚未结束"}, {a.TempUnschedulableUntil, "账号临时暂停尚未结束"},
  27. } {
  28. if item.deadline != nil && item.deadline.After(until) {
  29. until, reason = *item.deadline, item.reason
  30. }
  31. }
  32. if wait := a.GetModelRateLimitRemainingTimeWithContext(ctx, model); wait > 0 && now.Add(wait).After(until) {
  33. until, reason = now.Add(wait), "所选模型限流冷却尚未结束"
  34. }
  35. if reason != "" {
  36. return &TestAdmissionWaitError{Until: until, Reason: reason}
  37. }
  38. return nil
  39. }
  40. func (s *AccountTestService) acquireTestAccountSlot(ctx context.Context, a *Account) (func(), error) {
  41. // Production wiring supplies the shared service. Narrow standalone test
  42. // fixtures can omit it without creating an independent concurrency pool.
  43. if s.concurrencyService == nil {
  44. return func() {}, nil
  45. }
  46. result, err := s.concurrencyService.AcquireAccountSlot(ctx, a.ID, a.Mode1EffectiveConcurrency())
  47. if err != nil {
  48. return nil, fmt.Errorf("测试并发准入不可用: %w", err)
  49. }
  50. if !result.Acquired {
  51. return nil, ErrIntelligentAccountBusy
  52. }
  53. return result.ReleaseFunc, nil
  54. }