hub/internal/notification/dispatcher.go

84 lines
2.0 KiB
Go

package notification
import (
"context"
"sync"
"time"
"github.com/artifacthub/hub/internal/hub"
"github.com/patrickmn/go-cache"
"github.com/spf13/viper"
)
const (
defaultNumWorkers = 2
cacheDefaultExpiration = 5 * time.Minute
cacheCleanupInterval = 10 * time.Minute
)
// Services is a wrapper around several internal services used to handle
// notifications deliveries.
type Services struct {
DB hub.DB
ES hub.EmailSender
NotificationManager hub.NotificationManager
SubscriptionManager hub.SubscriptionManager
RepositoryManager hub.RepositoryManager
PackageManager hub.PackageManager
HTTPClient hub.HTTPClient
}
// Dispatcher handles a group of workers in charge of delivering notifications.
type Dispatcher struct {
numWorkers int
workers []*Worker
}
// NewDispatcher creates a new Dispatcher instance.
func NewDispatcher(cfg *viper.Viper, svc *Services, opts ...func(d *Dispatcher)) *Dispatcher {
// Setup dispatcher
d := &Dispatcher{
numWorkers: defaultNumWorkers,
}
for _, o := range opts {
o(d)
}
// Setup and launch workers
c := cache.New(cacheDefaultExpiration, cacheCleanupInterval)
baseURL := cfg.GetString("server.baseURL")
d.workers = make([]*Worker, 0, d.numWorkers)
for i := 0; i < d.numWorkers; i++ {
d.workers = append(d.workers, NewWorker(svc, c, baseURL))
}
return d
}
// WithNumWorkers allows providing a specific number of workers for a
// Dispatcher instance.
func WithNumWorkers(n int) func(d *Dispatcher) {
return func(d *Dispatcher) {
d.numWorkers = n
}
}
// Run starts the workers and lets them run until the dispatcher is asked to
// stop via the context provided.
func (d *Dispatcher) Run(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
// Start workers
wwg := &sync.WaitGroup{}
wctx, stopWorkers := context.WithCancel(context.Background())
for _, w := range d.workers {
wwg.Add(1)
go w.Run(wctx, wwg)
}
// Stop workers when dispatcher is asked to stop
<-ctx.Done()
stopWorkers()
wwg.Wait()
}