package application import ( "errors" "fmt" ) var ( // ErrServiceAlreadyRegistered returns if trying to register a service with name already taken by other service. ErrServiceAlreadyRegistered = errors.New("service with such name already registered") // ErrServiceNotFound returns if trying to gather service with unknown name. ErrServiceNotFound = errors.New("service with such name wasn't found") ) // Service is an interface every service should conform to. Specific services will have own interface for // cross-service interation. type Service interface { // Configure configures service. Called after ConnectDependencies and before LaunchStartupTasks. Configure() error // ConnectDependencies gets neccessary dependencies. ConnectDependencies() error // Initialize initializes service's internal state. Called while registering service with Application // lifecycle controller. Initialize() error // Name returns service name. Name() string // LaunchStartupTasks launches tasks on application start. Called after ConnectDependencies and Configure. LaunchStartupTasks() error // Shutdown stops service. Shutdown() error } // RegisterService registering service with lifecycle controller for later use in any other service. func (a *Application) RegisterService(srv Service) error { var found bool for _, knownService := range a.services { if srv.Name() == knownService.Name() { found = true break } } if found { return fmt.Errorf( "%w: RegisterService: check for service '%s' registration: %w", errApplication, srv.Name(), ErrServiceAlreadyRegistered, ) } if err := srv.Initialize(); err != nil { return fmt.Errorf("%w: RegisterService: initialize service '%s': %w", errApplication, srv.Name(), err) } a.services = append(a.services, srv) return nil } // Service returns requested service. func (a *Application) Service(name string) Service { var srv Service for _, knownService := range a.services { if knownService.Name() == name { srv = knownService break } } if srv == nil { return nil } return srv }