mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
96 lines
3.1 KiB
Go
96 lines
3.1 KiB
Go
package shared
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var log = logrus.WithField("prefix", "registry")
|
|
|
|
// Service is a struct that can be registered into a ServiceRegistry for
|
|
// easy dependency management.
|
|
type Service interface {
|
|
// Start spawns any goroutines required by the service.
|
|
Start()
|
|
// Stop terminates all goroutines belonging to the service,
|
|
// blocking until they are all terminated.
|
|
Stop() error
|
|
// Returns error if the service is not considered healthy.
|
|
Status() error
|
|
}
|
|
|
|
// ServiceRegistry provides a useful pattern for managing services.
|
|
// It allows for ease of dependency management and ensures services
|
|
// dependent on others use the same references in memory.
|
|
type ServiceRegistry struct {
|
|
services map[reflect.Type]Service // map of types to services.
|
|
serviceTypes []reflect.Type // keep an ordered slice of registered service types.
|
|
}
|
|
|
|
// NewServiceRegistry starts a registry instance for convenience
|
|
func NewServiceRegistry() *ServiceRegistry {
|
|
return &ServiceRegistry{
|
|
services: make(map[reflect.Type]Service),
|
|
}
|
|
}
|
|
|
|
// StartAll initialized each service in order of registration.
|
|
func (s *ServiceRegistry) StartAll() {
|
|
log.Infof("Starting %d services: %v", len(s.serviceTypes), s.serviceTypes)
|
|
for _, kind := range s.serviceTypes {
|
|
log.Debugf("Starting service type %v", kind)
|
|
s.services[kind].Start()
|
|
}
|
|
}
|
|
|
|
// StopAll ends every service in reverse order of registration, logging a
|
|
// panic if any of them fail to stop.
|
|
func (s *ServiceRegistry) StopAll() {
|
|
for i := len(s.serviceTypes) - 1; i >= 0; i-- {
|
|
kind := s.serviceTypes[i]
|
|
service := s.services[kind]
|
|
if err := service.Stop(); err != nil {
|
|
log.Panicf("Could not stop the following service: %v, %v", kind, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Statuses returns a map of Service type -> error. The map will be populated
|
|
// with the results of each service.Status() method call.
|
|
func (s *ServiceRegistry) Statuses() map[reflect.Type]error {
|
|
m := make(map[reflect.Type]error)
|
|
for _, kind := range s.serviceTypes {
|
|
m[kind] = s.services[kind].Status()
|
|
}
|
|
return m
|
|
}
|
|
|
|
// RegisterService appends a service constructor function to the service
|
|
// registry.
|
|
func (s *ServiceRegistry) RegisterService(service Service) error {
|
|
kind := reflect.TypeOf(service)
|
|
if _, exists := s.services[kind]; exists {
|
|
return fmt.Errorf("service already exists: %v", kind)
|
|
}
|
|
s.services[kind] = service
|
|
s.serviceTypes = append(s.serviceTypes, kind)
|
|
return nil
|
|
}
|
|
|
|
// FetchService takes in a struct pointer and sets the value of that pointer
|
|
// to a service currently stored in the service registry. This ensures the input argument is
|
|
// set to the right pointer that refers to the originally registered service.
|
|
func (s *ServiceRegistry) FetchService(service interface{}) error {
|
|
if reflect.TypeOf(service).Kind() != reflect.Ptr {
|
|
return fmt.Errorf("input must be of pointer type, received value type instead: %T", service)
|
|
}
|
|
element := reflect.ValueOf(service).Elem()
|
|
if running, ok := s.services[element.Type()]; ok {
|
|
element.Set(reflect.ValueOf(running))
|
|
return nil
|
|
}
|
|
return fmt.Errorf("unknown service: %T", service)
|
|
}
|