batch_image_worker_runtime.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package service
  2. import (
  3. "context"
  4. "sync"
  5. "github.com/Wei-Shaw/sub2api/internal/config"
  6. )
  7. type BatchImageWorkerRuntime struct {
  8. worker *BatchImageWorker
  9. billingRecovery *BatchImageBillingRecoveryService
  10. cfg *config.Config
  11. mu sync.Mutex
  12. cancel context.CancelFunc
  13. done chan struct{}
  14. }
  15. func NewBatchImageWorkerRuntime(worker *BatchImageWorker, cfg *config.Config) *BatchImageWorkerRuntime {
  16. return &BatchImageWorkerRuntime{worker: worker, cfg: cfg}
  17. }
  18. func ProvideBatchImageWorkerRuntime(
  19. repo BatchImageRepository,
  20. accountRepo AccountRepository,
  21. queue BatchImageQueue,
  22. billingRepo UsageBillingRepository,
  23. usageLogRepo UsageLogRepository,
  24. pricing *BatchImageModelPricingResolver,
  25. authCache APIKeyAuthCacheInvalidator,
  26. cfg *config.Config,
  27. ) *BatchImageWorkerRuntime {
  28. processor := &BatchImagePipelineProcessor{
  29. ProviderProcessor: &BatchImageProviderProcessor{
  30. Repo: repo,
  31. ProviderRegistry: NewBatchImageProviderRegistryFromConfig(cfg),
  32. AccountResolver: &BatchImageAccountRepositoryResolver{Repo: accountRepo},
  33. BillingRepo: billingRepo,
  34. AuthCache: authCache,
  35. },
  36. SettlementService: &BatchImageSettlementService{
  37. Repo: repo,
  38. BillingRepo: billingRepo,
  39. UsageLogRepo: usageLogRepo,
  40. Pricing: pricing,
  41. AuthCache: authCache,
  42. Config: cfg,
  43. },
  44. }
  45. runtime := NewBatchImageWorkerRuntime(NewBatchImageWorker(queue, processor, NewBatchImageWorkerOptionsFromConfig(cfg)), cfg)
  46. runtime.billingRecovery = &BatchImageBillingRecoveryService{
  47. Repo: repo,
  48. Billing: billingRepo,
  49. AuthCache: authCache,
  50. Queue: queue,
  51. StaleAfter: NewBatchImageWorkerOptionsFromConfig(cfg).StaleActiveAfter,
  52. Limit: NewBatchImageWorkerOptionsFromConfig(cfg).RecoverLimit,
  53. }
  54. runtime.Start()
  55. return runtime
  56. }
  57. func (r *BatchImageWorkerRuntime) Start() {
  58. if r == nil || r.worker == nil || r.cfg == nil || !r.cfg.BatchImage.QueueEnabled {
  59. return
  60. }
  61. r.mu.Lock()
  62. defer r.mu.Unlock()
  63. if r.cancel != nil {
  64. return
  65. }
  66. ctx, cancel := context.WithCancel(context.Background())
  67. done := make(chan struct{})
  68. r.cancel = cancel
  69. r.done = done
  70. var wg sync.WaitGroup
  71. wg.Add(4)
  72. go func() {
  73. defer wg.Done()
  74. r.worker.Run(ctx)
  75. }()
  76. go func() {
  77. defer wg.Done()
  78. r.worker.RunDelayedMover(ctx)
  79. }()
  80. go func() {
  81. defer wg.Done()
  82. r.worker.RunStaleActiveRecovery(ctx)
  83. }()
  84. go func() {
  85. defer wg.Done()
  86. r.runBillingRecovery(ctx)
  87. }()
  88. go func() {
  89. wg.Wait()
  90. close(done)
  91. }()
  92. }
  93. func (r *BatchImageWorkerRuntime) runBillingRecovery(ctx context.Context) {
  94. if r == nil || r.worker == nil || r.billingRecovery == nil {
  95. return
  96. }
  97. interval := r.worker.opts.RecoveryInterval
  98. for {
  99. if err := ctx.Err(); err != nil {
  100. return
  101. }
  102. _, _ = r.billingRecovery.ReleaseStaleUnsubmittedOnce(ctx)
  103. sleepOrDone(ctx, interval)
  104. }
  105. }
  106. func (r *BatchImageWorkerRuntime) Stop() {
  107. if r == nil {
  108. return
  109. }
  110. r.mu.Lock()
  111. cancel := r.cancel
  112. done := r.done
  113. r.cancel = nil
  114. r.done = nil
  115. r.mu.Unlock()
  116. if cancel != nil {
  117. cancel()
  118. }
  119. if done != nil {
  120. <-done
  121. }
  122. }
  123. func (r *BatchImageWorkerRuntime) Running() bool {
  124. if r == nil {
  125. return false
  126. }
  127. r.mu.Lock()
  128. defer r.mu.Unlock()
  129. return r.cancel != nil
  130. }