|
|
|
|
@ -8,19 +8,16 @@ import ( |
|
|
|
|
"github.com/grafana/dskit/services" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt" |
|
|
|
|
"github.com/grafana/grafana/pkg/setting" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type Engine interface { |
|
|
|
|
Init(context.Context) error |
|
|
|
|
Run(context.Context) error |
|
|
|
|
Shutdown(context.Context) error |
|
|
|
|
Shutdown(context.Context, string) error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type Manager interface { |
|
|
|
|
RegisterModule(name string, initFn func() (services.Service, error), deps ...string) |
|
|
|
|
RegisterInvisibleModule(name string, initFn func() (services.Service, error), deps ...string) |
|
|
|
|
RegisterModule(name string, fn initFn) |
|
|
|
|
RegisterInvisibleModule(name string, fn initFn) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var _ Engine = (*service)(nil) |
|
|
|
|
@ -28,89 +25,86 @@ var _ Manager = (*service)(nil) |
|
|
|
|
|
|
|
|
|
// service manages the registration and lifecycle of modules.
|
|
|
|
|
type service struct { |
|
|
|
|
cfg *setting.Cfg |
|
|
|
|
log log.Logger |
|
|
|
|
targets []string |
|
|
|
|
dependencyMap map[string][]string |
|
|
|
|
|
|
|
|
|
ModuleManager *modules.Manager |
|
|
|
|
ServiceManager *services.Manager |
|
|
|
|
ServiceMap map[string]services.Service |
|
|
|
|
log log.Logger |
|
|
|
|
targets []string |
|
|
|
|
|
|
|
|
|
moduleManager *modules.Manager |
|
|
|
|
serviceManager *services.Manager |
|
|
|
|
serviceMap map[string]services.Service |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func ProvideService( |
|
|
|
|
cfg *setting.Cfg, |
|
|
|
|
features *featuremgmt.FeatureManager, |
|
|
|
|
func New( |
|
|
|
|
targets []string, |
|
|
|
|
) *service { |
|
|
|
|
logger := log.New("modules") |
|
|
|
|
|
|
|
|
|
return &service{ |
|
|
|
|
cfg: cfg, |
|
|
|
|
log: logger, |
|
|
|
|
targets: cfg.Target, |
|
|
|
|
dependencyMap: map[string][]string{}, |
|
|
|
|
log: logger, |
|
|
|
|
targets: targets, |
|
|
|
|
|
|
|
|
|
ModuleManager: modules.NewManager(logger), |
|
|
|
|
ServiceMap: map[string]services.Service{}, |
|
|
|
|
moduleManager: modules.NewManager(logger), |
|
|
|
|
serviceMap: map[string]services.Service{}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Init initializes all registered modules.
|
|
|
|
|
func (m *service) Init(_ context.Context) error { |
|
|
|
|
// Run starts all registered modules.
|
|
|
|
|
func (m *service) Run(ctx context.Context) error { |
|
|
|
|
var err error |
|
|
|
|
|
|
|
|
|
for mod, targets := range m.dependencyMap { |
|
|
|
|
if err := m.ModuleManager.AddDependency(mod, targets...); err != nil { |
|
|
|
|
for mod, targets := range dependencyMap { |
|
|
|
|
if !m.moduleManager.IsModuleRegistered(mod) { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if err := m.moduleManager.AddDependency(mod, targets...); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m.ServiceMap, err = m.ModuleManager.InitModuleServices(m.targets...) |
|
|
|
|
m.serviceMap, err = m.moduleManager.InitModuleServices(m.targets...) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// if no modules are registered, we don't need to start the service manager
|
|
|
|
|
if len(m.ServiceMap) == 0 { |
|
|
|
|
if len(m.serviceMap) == 0 { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var svcs []services.Service |
|
|
|
|
for _, s := range m.ServiceMap { |
|
|
|
|
for _, s := range m.serviceMap { |
|
|
|
|
svcs = append(svcs, s) |
|
|
|
|
} |
|
|
|
|
m.ServiceManager, err = services.NewManager(svcs...) |
|
|
|
|
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
m.serviceManager, err = services.NewManager(svcs...) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Run starts all registered modules.
|
|
|
|
|
func (m *service) Run(ctx context.Context) error { |
|
|
|
|
// we don't need to continue if no modules are registered.
|
|
|
|
|
// this behavior may need to change if dskit services replace the
|
|
|
|
|
// current background service registry.
|
|
|
|
|
if len(m.ServiceMap) == 0 { |
|
|
|
|
if len(m.serviceMap) == 0 { |
|
|
|
|
m.log.Warn("No modules registered...") |
|
|
|
|
<-ctx.Done() |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listener := newServiceListener(m.log, m) |
|
|
|
|
m.ServiceManager.AddListener(listener) |
|
|
|
|
m.serviceManager.AddListener(listener) |
|
|
|
|
|
|
|
|
|
m.log.Debug("Starting module service manager") |
|
|
|
|
// wait until a service fails or stop signal was received
|
|
|
|
|
err := m.ServiceManager.StartAsync(ctx) |
|
|
|
|
err = m.serviceManager.StartAsync(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err = m.ServiceManager.AwaitStopped(ctx) |
|
|
|
|
err = m.serviceManager.AwaitStopped(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
failed := m.ServiceManager.ServicesByState()[services.Failed] |
|
|
|
|
failed := m.serviceManager.ServicesByState()[services.Failed] |
|
|
|
|
for _, f := range failed { |
|
|
|
|
// the service listener will log error details for all modules that failed,
|
|
|
|
|
// so here we return the first error that is not ErrStopProcess
|
|
|
|
|
@ -123,27 +117,27 @@ func (m *service) Run(ctx context.Context) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Shutdown stops all modules and waits for them to stop.
|
|
|
|
|
func (m *service) Shutdown(ctx context.Context) error { |
|
|
|
|
if m.ServiceManager == nil { |
|
|
|
|
func (m *service) Shutdown(ctx context.Context, reason string) error { |
|
|
|
|
if m.serviceManager == nil { |
|
|
|
|
m.log.Debug("No modules registered, nothing to stop...") |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
m.ServiceManager.StopAsync() |
|
|
|
|
m.log.Info("Awaiting services to be stopped...") |
|
|
|
|
return m.ServiceManager.AwaitStopped(ctx) |
|
|
|
|
m.serviceManager.StopAsync() |
|
|
|
|
m.log.Info("Awaiting services to be stopped...", "reason", reason) |
|
|
|
|
return m.serviceManager.AwaitStopped(ctx) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type initFn func() (services.Service, error) |
|
|
|
|
|
|
|
|
|
// RegisterModule registers a module with the dskit module manager.
|
|
|
|
|
func (m *service) RegisterModule(name string, initFn func() (services.Service, error), deps ...string) { |
|
|
|
|
m.ModuleManager.RegisterModule(name, initFn) |
|
|
|
|
m.dependencyMap[name] = deps |
|
|
|
|
func (m *service) RegisterModule(name string, fn initFn) { |
|
|
|
|
m.moduleManager.RegisterModule(name, fn) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RegisterInvisibleModule registers an invisible module with the dskit module manager.
|
|
|
|
|
// Invisible modules are not visible to the user, and are intendent to be used as dependencies.
|
|
|
|
|
func (m *service) RegisterInvisibleModule(name string, initFn func() (services.Service, error), deps ...string) { |
|
|
|
|
m.ModuleManager.RegisterModule(name, initFn, modules.UserInvisibleModule) |
|
|
|
|
m.dependencyMap[name] = deps |
|
|
|
|
func (m *service) RegisterInvisibleModule(name string, fn initFn) { |
|
|
|
|
m.moduleManager.RegisterModule(name, fn, modules.UserInvisibleModule) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// IsModuleEnabled returns true if the module is enabled.
|
|
|
|
|
|