github.com/Financial-Times/publish-availability-monitor@v1.12.0/feeds/notificationsPullFeed.go (about)

     1  package feeds
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/url"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/Financial-Times/go-logger/v2"
    10  	"github.com/Financial-Times/publish-availability-monitor/httpcaller"
    11  )
    12  
    13  const NotificationsPull = "Notifications-Pull"
    14  
    15  type NotificationsPullFeed struct {
    16  	baseNotificationsFeed
    17  	notificationsURL         string
    18  	notificationsQueryString string
    19  	notificationsURLLock     *sync.Mutex
    20  	interval                 int
    21  	ticker                   *time.Ticker
    22  	poller                   chan struct{}
    23  	log                      *logger.UPPLogger
    24  }
    25  
    26  // ignore unused field (e.g. requestUrl)
    27  type notificationsResponse struct {
    28  	Notifications []Notification
    29  	Links         []Link
    30  }
    31  
    32  func (f *NotificationsPullFeed) Start() {
    33  	if f.httpCaller == nil {
    34  		f.httpCaller = httpcaller.NewCaller(10)
    35  	}
    36  
    37  	f.ticker = time.NewTicker(time.Duration(f.interval) * time.Second)
    38  	f.poller = make(chan struct{})
    39  	go func() {
    40  		for {
    41  			select {
    42  			case <-f.ticker.C:
    43  				go func() {
    44  					f.pollNotificationsFeed()
    45  					f.purgeObsoleteNotifications()
    46  				}()
    47  			case <-f.poller:
    48  				f.ticker.Stop()
    49  				return
    50  			}
    51  		}
    52  	}()
    53  }
    54  
    55  func (f *NotificationsPullFeed) Stop() {
    56  	f.log.Infof("shutting down notifications pull feed for %s", f.baseURL)
    57  	close(f.poller)
    58  }
    59  
    60  func (f *NotificationsPullFeed) FeedType() string {
    61  	return NotificationsPull
    62  }
    63  
    64  func (f *NotificationsPullFeed) pollNotificationsFeed() {
    65  	f.notificationsURLLock.Lock()
    66  	defer f.notificationsURLLock.Unlock()
    67  
    68  	tid := f.buildNotificationsTID()
    69  	log := f.log.WithTransactionID(tid)
    70  	notificationsURL := f.notificationsURL + "?" + f.notificationsQueryString
    71  
    72  	resp, err := f.httpCaller.DoCall(httpcaller.Config{
    73  		URL:      notificationsURL,
    74  		Username: f.username,
    75  		Password: f.password,
    76  		TID:      tid,
    77  	})
    78  	if err != nil {
    79  		log.WithError(err).Errorf("error calling notifications %s", notificationsURL)
    80  		return
    81  	}
    82  	defer func() {
    83  		_ = resp.Body.Close()
    84  	}()
    85  
    86  	if resp.StatusCode != 200 {
    87  		log.Errorf("Notifications [%s] status NOT OK: [%d]", notificationsURL, resp.StatusCode)
    88  		return
    89  	}
    90  
    91  	var notifications notificationsResponse
    92  	err = json.NewDecoder(resp.Body).Decode(&notifications)
    93  	if err != nil {
    94  		log.WithError(err).Error("Cannot decode json response")
    95  		return
    96  	}
    97  
    98  	f.notificationsLock.Lock()
    99  	defer f.notificationsLock.Unlock()
   100  
   101  	for _, v := range notifications.Notifications {
   102  		n := v
   103  		uuid := parseUUIDFromURL(n.ID)
   104  		var history []*Notification
   105  		var found bool
   106  		if history, found = f.notifications[uuid]; !found {
   107  			history = make([]*Notification, 0)
   108  		}
   109  
   110  		history = append(history, &n)
   111  		f.notifications[uuid] = history
   112  	}
   113  
   114  	nextPageURL, err := url.Parse(notifications.Links[0].Href)
   115  	if err != nil {
   116  		log.WithError(err).Errorf("unparseable next url: [%s]", notifications.Links[0].Href)
   117  		return // and hope that a retry will fix this
   118  	}
   119  
   120  	f.notificationsQueryString = nextPageURL.RawQuery
   121  }
   122  
   123  func (f *NotificationsPullFeed) buildNotificationsTID() string {
   124  	return "tid_pam_notifications_pull_" + time.Now().Format(time.RFC3339)
   125  }