fixes
This commit is contained in:
parent
21a0856587
commit
e8dc967e6a
26 changed files with 1373 additions and 481 deletions
|
|
@ -2,59 +2,69 @@ package broadcast
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// defaultInterval/defaultBatch match the shipped
|
||||
// TELESRV_BROADCAST_WORKER_INTERVAL/_BATCH defaults.
|
||||
const (
|
||||
defaultInterval = 3 * time.Second
|
||||
defaultBatch = 50
|
||||
)
|
||||
// WorkerConfig tunes the periodic materialize+delivery cycle. Non-positive
|
||||
// or out-of-range fields fall back to the defaults below (matching the
|
||||
// shipped TELESRV_BROADCAST_WORKER_* defaults).
|
||||
type WorkerConfig struct {
|
||||
Interval time.Duration
|
||||
Lease time.Duration
|
||||
MaterializeBatch int
|
||||
DeliveryBatch int
|
||||
}
|
||||
|
||||
// Worker drains the broadcast delivery outbox.
|
||||
// Worker drains the broadcast delivery outbox and, for "all"-mode
|
||||
// campaigns, the recipient-enumeration backlog.
|
||||
//
|
||||
// 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.
|
||||
// A broadcast is created together with only its target snapshot, never with
|
||||
// the enumeration or the sends themselves: an admin creating a broadcast for
|
||||
// every user must not wait on however long that would take. Both
|
||||
// materialization and delivery are 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
|
||||
service *Service
|
||||
config WorkerConfig
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
// 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()
|
||||
// NewWorker creates the periodic worker.
|
||||
func NewWorker(service *Service, config WorkerConfig, log *zap.Logger) *Worker {
|
||||
if config.Interval <= 0 {
|
||||
config.Interval = 3 * time.Second
|
||||
}
|
||||
if interval <= 0 {
|
||||
interval = defaultInterval
|
||||
if config.Lease <= 0 {
|
||||
config.Lease = 30 * time.Second
|
||||
}
|
||||
if batch <= 0 {
|
||||
batch = defaultBatch
|
||||
if config.MaterializeBatch <= 0 || config.MaterializeBatch > 1000 {
|
||||
config.MaterializeBatch = 200
|
||||
}
|
||||
return &Worker{service: service, logger: logger, interval: interval, batch: batch}
|
||||
if config.DeliveryBatch <= 0 || config.DeliveryBatch > 500 {
|
||||
config.DeliveryBatch = 50
|
||||
}
|
||||
if log == nil {
|
||||
log = zap.NewNop()
|
||||
}
|
||||
return &Worker{service: service, config: config, log: log}
|
||||
}
|
||||
|
||||
// Run delivers one batch immediately and then on every tick until ctx is
|
||||
// Run advances one cycle 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")
|
||||
if w == nil || w.service == nil || !w.service.Ready() {
|
||||
if w != nil && w.log != nil {
|
||||
w.log.Info("broadcast delivery worker disabled: not configured")
|
||||
}
|
||||
return
|
||||
}
|
||||
w.runOnce(ctx)
|
||||
ticker := time.NewTicker(w.interval)
|
||||
ticker := time.NewTicker(w.config.Interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
|
|
@ -67,18 +77,23 @@ func (w *Worker) Run(ctx context.Context) {
|
|||
}
|
||||
|
||||
func (w *Worker) runOnce(ctx context.Context) {
|
||||
if w == nil || w.service == nil {
|
||||
var tokenBytes [16]byte
|
||||
if _, err := rand.Read(tokenBytes[:]); err != nil {
|
||||
w.log.Error("generate broadcast lease token", zap.Error(err))
|
||||
return
|
||||
}
|
||||
sent, err := w.service.RunSendCycle(ctx, w.batch)
|
||||
result, err := w.service.RunCycle(ctx, hex.EncodeToString(tokenBytes[:]), w.config.MaterializeBatch, w.config.DeliveryBatch, w.config.Lease)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
if ctx.Err() == nil {
|
||||
w.log.Warn("broadcast delivery cycle failed", zap.Error(err))
|
||||
}
|
||||
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))
|
||||
if result.Materialized > 0 || result.Claimed > 0 {
|
||||
w.log.Info("broadcast delivery cycle completed",
|
||||
zap.Int("materialized", result.Materialized),
|
||||
zap.Int("claimed", result.Claimed),
|
||||
zap.Int("sent", result.Sent),
|
||||
zap.Int("failed", result.Failed))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue