github.com/prysmaticlabs/prysm@v1.4.4/shared/service_registry.go (about)

     1  // Package shared includes useful utilities globally accessible in
     2  // the Prysm monorepo.
     3  package shared
     4  
     5  import (
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/sirupsen/logrus"
    10  )
    11  
    12  var log = logrus.WithField("prefix", "registry")
    13  
    14  // Service is a struct that can be registered into a ServiceRegistry for
    15  // easy dependency management.
    16  type Service interface {
    17  	// Start spawns any goroutines required by the service.
    18  	Start()
    19  	// Stop terminates all goroutines belonging to the service,
    20  	// blocking until they are all terminated.
    21  	Stop() error
    22  	// Status returns error if the service is not considered healthy.
    23  	Status() error
    24  }
    25  
    26  // ServiceRegistry provides a useful pattern for managing services.
    27  // It allows for ease of dependency management and ensures services
    28  // dependent on others use the same references in memory.
    29  type ServiceRegistry struct {
    30  	services     map[reflect.Type]Service // map of types to services.
    31  	serviceTypes []reflect.Type           // keep an ordered slice of registered service types.
    32  }
    33  
    34  // NewServiceRegistry starts a registry instance for convenience
    35  func NewServiceRegistry() *ServiceRegistry {
    36  	return &ServiceRegistry{
    37  		services: make(map[reflect.Type]Service),
    38  	}
    39  }
    40  
    41  // StartAll initialized each service in order of registration.
    42  func (s *ServiceRegistry) StartAll() {
    43  	log.Debugf("Starting %d services: %v", len(s.serviceTypes), s.serviceTypes)
    44  	for _, kind := range s.serviceTypes {
    45  		log.Debugf("Starting service type %v", kind)
    46  		go s.services[kind].Start()
    47  	}
    48  }
    49  
    50  // StopAll ends every service in reverse order of registration, logging a
    51  // panic if any of them fail to stop.
    52  func (s *ServiceRegistry) StopAll() {
    53  	for i := len(s.serviceTypes) - 1; i >= 0; i-- {
    54  		kind := s.serviceTypes[i]
    55  		service := s.services[kind]
    56  		if err := service.Stop(); err != nil {
    57  			log.WithError(err).Errorf("Could not stop the following service: %v", kind)
    58  		}
    59  	}
    60  }
    61  
    62  // Statuses returns a map of Service type -> error. The map will be populated
    63  // with the results of each service.Status() method call.
    64  func (s *ServiceRegistry) Statuses() map[reflect.Type]error {
    65  	m := make(map[reflect.Type]error, len(s.serviceTypes))
    66  	for _, kind := range s.serviceTypes {
    67  		m[kind] = s.services[kind].Status()
    68  	}
    69  	return m
    70  }
    71  
    72  // RegisterService appends a service constructor function to the service
    73  // registry.
    74  func (s *ServiceRegistry) RegisterService(service Service) error {
    75  	kind := reflect.TypeOf(service)
    76  	if _, exists := s.services[kind]; exists {
    77  		return fmt.Errorf("service already exists: %v", kind)
    78  	}
    79  	s.services[kind] = service
    80  	s.serviceTypes = append(s.serviceTypes, kind)
    81  	return nil
    82  }
    83  
    84  // FetchService takes in a struct pointer and sets the value of that pointer
    85  // to a service currently stored in the service registry. This ensures the input argument is
    86  // set to the right pointer that refers to the originally registered service.
    87  func (s *ServiceRegistry) FetchService(service interface{}) error {
    88  	if reflect.TypeOf(service).Kind() != reflect.Ptr {
    89  		return fmt.Errorf("input must be of pointer type, received value type instead: %T", service)
    90  	}
    91  	element := reflect.ValueOf(service).Elem()
    92  	if running, ok := s.services[element.Type()]; ok {
    93  		element.Set(reflect.ValueOf(running))
    94  		return nil
    95  	}
    96  	return fmt.Errorf("unknown service: %T", service)
    97  }