github.com/blend/go-sdk@v1.20220411.3/status/tracked_action_aggregator.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package status
     9  
    10  import (
    11  	"net/http"
    12  	"sort"
    13  
    14  	"github.com/blend/go-sdk/async"
    15  	"github.com/blend/go-sdk/logger"
    16  	"github.com/blend/go-sdk/web"
    17  )
    18  
    19  // NewTrackedActionAggregator returns a new tracked action aggregator.
    20  func NewTrackedActionAggregator(trackedActions ...*TrackedAction) *TrackedActionAggregator {
    21  	taa := &TrackedActionAggregator{
    22  		TrackedActions: make(map[string]*TrackedAction),
    23  	}
    24  	for index := range trackedActions {
    25  		trackedAction := trackedActions[index]
    26  		taa.TrackedActions[trackedAction.ServiceName] = trackedAction
    27  	}
    28  	return taa
    29  }
    30  
    31  // TrackedActionAggregator aggregates tracker results.
    32  type TrackedActionAggregator struct {
    33  	TrackedActions map[string]*TrackedAction
    34  	Log            logger.Log
    35  }
    36  
    37  // Interceptor returns a new tracked action.
    38  func (taa *TrackedActionAggregator) Interceptor(serviceName string, opts ...TrackedActionOption) async.Interceptor {
    39  	trackedAction := NewTrackedAction(serviceName, opts...)
    40  	taa.TrackedActions[serviceName] = trackedAction
    41  	return trackedAction
    42  }
    43  
    44  // Endpoint implements the endpoint.
    45  func (taa *TrackedActionAggregator) Endpoint(servicesToCheck ...string) web.Action {
    46  	return func(r *web.Ctx) web.Result {
    47  		statuses := make(map[string]Info)
    48  		for _, serviceName := range taa.servicesOrDefault(servicesToCheck...) {
    49  			if tracker, ok := taa.TrackedActions[serviceName]; ok {
    50  				statuses[serviceName] = tracker.GetStatus()
    51  			}
    52  		}
    53  		statusCode := http.StatusOK
    54  		status := taa.getSummarySignal(statuses)
    55  		if status != SignalGreen {
    56  			statusCode = http.StatusServiceUnavailable
    57  		}
    58  		return web.JSON.Status(statusCode, TrackedActionsResult{
    59  			Status:     status,
    60  			SubSystems: statuses,
    61  		})
    62  	}
    63  }
    64  
    65  //
    66  // Private / Internal
    67  //
    68  
    69  // getSummarySignal implements a this or that (green | red) based on if _any_ of the infos aren't green.
    70  func (taa TrackedActionAggregator) getSummarySignal(statuses map[string]Info) (signal Signal) {
    71  	signal = SignalGreen
    72  	for _, status := range statuses {
    73  		if status.Status != SignalGreen {
    74  			signal = SignalRed
    75  			return
    76  		}
    77  	}
    78  	return
    79  }
    80  
    81  // servicesOrDefault returns either the servicesToCheck list if it is set
    82  // or all the keys in the detailed service checks.
    83  func (taa TrackedActionAggregator) servicesOrDefault(servicesToCheck ...string) []string {
    84  	if len(servicesToCheck) > 0 {
    85  		return servicesToCheck
    86  	}
    87  	var output []string
    88  	for key := range taa.TrackedActions {
    89  		output = append(output, key)
    90  	}
    91  	sort.Strings(output)
    92  	return output
    93  }