Files
dygou_go/internal/image/queue.go
T

102 lines
2.1 KiB
Go

package image
import (
"sync"
"github.com/golang/freetype/truetype"
"douyu_go/internal/logger"
"douyu_go/internal/types"
)
const (
defaultSuccessImageWorkers = 1
defaultSuccessImageQueue = 256
)
type successImageJob struct {
Account types.Account
Product types.Product
RoleName string
}
// SuccessImageSaver 用后台队列生成成功图片,避免图片编码和磁盘写入占用抢购链路。
type SuccessImageSaver struct {
font *truetype.Font
successDir string
ch chan successImageJob
wg sync.WaitGroup
mu sync.Mutex
closed bool
}
// NewSuccessImageSaver 创建成功图片后台保存器。
func NewSuccessImageSaver(font *truetype.Font, successDir string, workers, queueSize int) *SuccessImageSaver {
if font == nil {
return nil
}
if workers <= 0 {
workers = defaultSuccessImageWorkers
}
if queueSize <= 0 {
queueSize = defaultSuccessImageQueue
}
saver := &SuccessImageSaver{
font: font,
successDir: successDir,
ch: make(chan successImageJob, queueSize),
}
for i := 0; i < workers; i++ {
saver.wg.Add(1)
go saver.run()
}
return saver
}
// Enqueue 投递成功图片任务;队列满时丢弃图片任务,优先保护抢购请求。
func (s *SuccessImageSaver) Enqueue(account types.Account, product types.Product, roleName string) {
if s == nil {
return
}
job := successImageJob{
Account: account,
Product: product,
RoleName: roleName,
}
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return
}
select {
case s.ch <- job:
default:
logger.LogEvent("图片", "warn", "成功图片队列已满,已跳过: 账号=%s 商品=%s", account.Name, product.CommodityID)
}
}
func (s *SuccessImageSaver) run() {
defer s.wg.Done()
for job := range s.ch {
SaveSuccessImage(job.Account, job.Product, job.RoleName, s.font, s.successDir)
}
}
// Close 关闭后台队列并等待已投递图片保存完成。
func (s *SuccessImageSaver) Close() {
if s == nil {
return
}
s.mu.Lock()
if s.closed {
s.mu.Unlock()
return
}
s.closed = true
close(s.ch)
s.mu.Unlock()
s.wg.Wait()
}