package dispatcher import ( "log" "math" "math/rand" "sync" "time" ) // Dispatcher - type Dispatcher struct { subscribers map[int]dispatchSubscriber subscribersMux *sync.Mutex } type dispatchSubscriber struct { notifyCancelOrCloseChan chan error closeCh <-chan struct{} } // NewDispatcher - func NewDispatcher() *Dispatcher { return &Dispatcher{ subscribers: make(map[int]dispatchSubscriber), subscribersMux: &sync.Mutex{}, } } // Dispatch - func (d *Dispatcher) Dispatch(err error) error { d.subscribersMux.Lock() defer d.subscribersMux.Unlock() for _, subscriber := range d.subscribers { select { case <-time.After(time.Second * 5): log.Println("Unexpected rabbitmq error: timeout in dispatch") case subscriber.notifyCancelOrCloseChan <- err: } } return nil } // AddSubscriber - func (d *Dispatcher) AddSubscriber() (<-chan error, chan<- struct{}) { const maxRand = math.MaxInt64 const minRand = 0 id := rand.Intn(maxRand-minRand) + minRand closeCh := make(chan struct{}) notifyCancelOrCloseChan := make(chan error) d.subscribersMux.Lock() d.subscribers[id] = dispatchSubscriber{ notifyCancelOrCloseChan: notifyCancelOrCloseChan, closeCh: closeCh, } d.subscribersMux.Unlock() go func(id int) { <-closeCh d.subscribersMux.Lock() defer d.subscribersMux.Unlock() sub, ok := d.subscribers[id] if !ok { return } close(sub.notifyCancelOrCloseChan) delete(d.subscribers, id) }(id) return notifyCancelOrCloseChan, closeCh }