github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/notifier.go (about)

     1  package db
     2  
     3  import "time"
     4  
     5  //go:generate counterfeiter . Notifier
     6  
     7  type Notifier interface {
     8  	Notify() <-chan struct{}
     9  	Close() error
    10  }
    11  
    12  func newConditionNotifier(bus NotificationsBus, channel string, cond func() (bool, error)) (Notifier, error) {
    13  	notified, err := bus.Listen(channel)
    14  	if err != nil {
    15  		return nil, err
    16  	}
    17  
    18  	notifier := &conditionNotifier{
    19  		cond:    cond,
    20  		bus:     bus,
    21  		channel: channel,
    22  
    23  		notified: notified,
    24  		notify:   make(chan struct{}, 1),
    25  
    26  		stop: make(chan struct{}),
    27  	}
    28  
    29  	go notifier.watch()
    30  
    31  	return notifier, nil
    32  }
    33  
    34  type conditionNotifier struct {
    35  	cond func() (bool, error)
    36  
    37  	bus     NotificationsBus
    38  	channel string
    39  
    40  	notified chan bool
    41  	notify   chan struct{}
    42  
    43  	stop chan struct{}
    44  }
    45  
    46  func (notifier *conditionNotifier) Notify() <-chan struct{} {
    47  	return notifier.notify
    48  }
    49  
    50  func (notifier *conditionNotifier) Close() error {
    51  	close(notifier.stop)
    52  	return notifier.bus.Unlisten(notifier.channel, notifier.notified)
    53  }
    54  
    55  func (notifier *conditionNotifier) watch() {
    56  	for {
    57  		c, err := notifier.cond()
    58  		if err != nil {
    59  			select {
    60  			case <-time.After(5 * time.Second):
    61  				continue
    62  			case <-notifier.stop:
    63  				return
    64  			}
    65  		}
    66  
    67  		if c {
    68  			notifier.sendNotification()
    69  		}
    70  
    71  	dance:
    72  		for {
    73  			select {
    74  			case <-notifier.stop:
    75  				return
    76  			case ok := <-notifier.notified:
    77  				if ok {
    78  					notifier.sendNotification()
    79  				} else {
    80  					break dance
    81  				}
    82  			}
    83  		}
    84  	}
    85  }
    86  
    87  func (notifier *conditionNotifier) sendNotification() {
    88  	select {
    89  	case notifier.notify <- struct{}{}:
    90  	default:
    91  	}
    92  }