87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"git.ipao.vip/rogee/creator-hub/internal/creator"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type listenerCoverWriter interface {
|
|
UpdateListenerEventCovers(context.Context, string, string, []creator.ListenerDelivery) error
|
|
}
|
|
type listenerCoverEnricher interface {
|
|
enrich(context.Context, []creator.ListenerDelivery) ([]creator.ListenerDelivery, error)
|
|
}
|
|
|
|
const coverQueueFullReason = "封面待处理队列已满,等待历史核对重试"
|
|
|
|
// The account receiver is the sole producer: prepare before persistence, submit
|
|
// after commit. Queue overload is recorded in that same transaction, never by
|
|
// a second synchronous database write on the event acknowledgement path.
|
|
func startListenerCoverWorker(ctx context.Context, store listenerWriter, accountID, generation string, session listenerSession) func([]creator.ListenerDelivery) func() {
|
|
noop := func() {}
|
|
writer, ok := store.(listenerCoverWriter)
|
|
enricher, has := session.(listenerCoverEnricher)
|
|
if !ok || !has {
|
|
return func([]creator.ListenerDelivery) func() { return noop }
|
|
}
|
|
jobs := make(chan []creator.ListenerDelivery, 32)
|
|
log := logrus.WithFields(logrus.Fields{"account_id": accountID, "generation": generation})
|
|
save := func(items []creator.ListenerDelivery) {
|
|
if err := writer.UpdateListenerEventCovers(ctx, accountID, generation, items); err != nil {
|
|
if !errors.Is(err, creator.ErrConflict) && ctx.Err() == nil {
|
|
log.WithError(err).Error("persist event cover result failed")
|
|
}
|
|
return
|
|
}
|
|
publishEventChanges(ctx)
|
|
}
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case items := <-jobs:
|
|
result, err := enricher.enrich(ctx, items)
|
|
if err != nil {
|
|
log.WithError(err).Error("event cover enrichment failed")
|
|
for i := range items {
|
|
items[i].Notice.WorkCoverError = err.Error()
|
|
}
|
|
save(items)
|
|
} else {
|
|
save(result)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
return func(items []creator.ListenerDelivery) func() {
|
|
pending := make([]creator.ListenerDelivery, 0, len(items))
|
|
for _, d := range items {
|
|
if d.Notice != nil && d.Notice.WorkID != "" && d.Notice.WorkCoverURL != "" {
|
|
copy := *d.Notice
|
|
d.Notice = ©
|
|
pending = append(pending, d)
|
|
}
|
|
}
|
|
if len(pending) == 0 {
|
|
return noop
|
|
}
|
|
if len(jobs) == cap(jobs) {
|
|
log.Error("event cover queue full; recording overload with notification persistence")
|
|
for i, d := range items {
|
|
if d.Notice != nil && d.Notice.WorkID != "" && d.Notice.WorkCoverURL != "" {
|
|
copy := *d.Notice
|
|
copy.WorkCoverError = coverQueueFullReason
|
|
items[i].Notice = ©
|
|
}
|
|
}
|
|
return noop
|
|
}
|
|
// No other producer can fill this capacity between prepare and commit.
|
|
return func() { jobs <- pending }
|
|
}
|
|
}
|