owpengram-server/internal/app/broadcast/worker.go
2026-08-06 15:22:36 +03:00

84 lines
2.1 KiB
Go

package broadcast
import (
"context"
"time"
"go.uber.org/zap"
)
// defaultInterval/defaultBatch match the shipped
// TELESRV_BROADCAST_WORKER_INTERVAL/_BATCH defaults.
const (
defaultInterval = 3 * time.Second
defaultBatch = 50
)
// Worker drains the broadcast delivery outbox.
//
// A broadcast is created together with its recipient snapshot, never with the
// sends themselves: an admin creating a broadcast for every user must not
// wait on however long that takes. Delivery is therefore a separate,
// retrying cycle over durable rows, and this worker is only its cadence.
type Worker struct {
service *Service
logger *zap.Logger
interval time.Duration
batch int
}
// NewWorker creates the periodic delivery worker. Non-positive
// interval/batch fall back to the shipped defaults.
func NewWorker(service *Service, logger *zap.Logger, interval time.Duration, batch int) *Worker {
if logger == nil {
logger = zap.NewNop()
}
if interval <= 0 {
interval = defaultInterval
}
if batch <= 0 {
batch = defaultBatch
}
return &Worker{service: service, logger: logger, interval: interval, batch: batch}
}
// Run delivers one batch immediately and then on every tick until ctx is
// done. A not-ready service (missing store/sender) exits immediately with
// one explicit log line instead of ticking forever over a no-op.
func (w *Worker) Run(ctx context.Context) {
if w == nil {
return
}
if !w.service.Ready() {
w.logger.Info("broadcast delivery worker disabled: not configured")
return
}
w.runOnce(ctx)
ticker := time.NewTicker(w.interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
w.runOnce(ctx)
}
}
}
func (w *Worker) runOnce(ctx context.Context) {
if w == nil || w.service == nil {
return
}
sent, err := w.service.RunSendCycle(ctx, w.batch)
if err != nil {
if ctx.Err() != nil {
return
}
w.logger.Warn("broadcast delivery cycle failed", zap.Int("sent", sent), zap.Int("batch", w.batch), zap.Error(err))
return
}
if sent > 0 {
w.logger.Info("broadcast delivery cycle completed", zap.Int("sent", sent), zap.Int("batch", w.batch))
}
}