registry.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package registry
  2. import (
  3. "context"
  4. "reflect"
  5. "sort"
  6. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
  7. )
  8. type Descriptor struct {
  9. Name string
  10. Instance Service
  11. InitPriority Priority
  12. }
  13. var services []*Descriptor
  14. func RegisterService(instance Service) {
  15. services = append(services, &Descriptor{
  16. Name: reflect.TypeOf(instance).Elem().Name(),
  17. Instance: instance,
  18. InitPriority: Low,
  19. })
  20. }
  21. func Register(descriptor *Descriptor) {
  22. services = append(services, descriptor)
  23. }
  24. func GetServices() []*Descriptor {
  25. slice := getServicesWithOverrides()
  26. sort.Slice(slice, func(i, j int) bool {
  27. return slice[i].InitPriority > slice[j].InitPriority
  28. })
  29. return slice
  30. }
  31. type OverrideServiceFunc func(descriptor Descriptor) (*Descriptor, bool)
  32. var overrides []OverrideServiceFunc
  33. func RegisterOverride(fn OverrideServiceFunc) {
  34. overrides = append(overrides, fn)
  35. }
  36. func getServicesWithOverrides() []*Descriptor {
  37. slice := []*Descriptor{}
  38. for _, s := range services {
  39. var descriptor *Descriptor
  40. for _, fn := range overrides {
  41. if newDescriptor, override := fn(*s); override {
  42. descriptor = newDescriptor
  43. break
  44. }
  45. }
  46. if descriptor != nil {
  47. slice = append(slice, descriptor)
  48. } else {
  49. slice = append(slice, s)
  50. }
  51. }
  52. return slice
  53. }
  54. // Service interface is the lowest common shape that services
  55. // are expected to forfill to be started within Grafana.
  56. type Service interface {
  57. // Init is called by Grafana main process which gives the service
  58. // the possibility do some initial work before its started. Things
  59. // like adding routes, bus handlers should be done in the Init function
  60. Init() error
  61. }
  62. // CanBeDisabled allows the services to decide if it should
  63. // be started or not by itself. This is useful for services
  64. // that might not always be started, ex alerting.
  65. // This will be called after `Init()`.
  66. type CanBeDisabled interface {
  67. // IsDisabled should return a bool saying if it can be started or not.
  68. IsDisabled() bool
  69. }
  70. // BackgroundService should be implemented for services that have
  71. // long running tasks in the background.
  72. type BackgroundService interface {
  73. // Run starts the background process of the service after `Init` have been called
  74. // on all services. The `context.Context` passed into the function should be used
  75. // to subscribe to ctx.Done() so the service can be notified when Grafana shuts down.
  76. Run(ctx context.Context) error
  77. }
  78. // DatabaseMigrator allows the caller to add migrations to
  79. // the migrator passed as argument
  80. type DatabaseMigrator interface {
  81. // AddMigrations allows the service to add migrations to
  82. // the database migrator.
  83. AddMigration(mg *migrator.Migrator)
  84. }
  85. // IsDisabled takes an service and return true if its disabled
  86. func IsDisabled(srv Service) bool {
  87. canBeDisabled, ok := srv.(CanBeDisabled)
  88. return ok && canBeDisabled.IsDisabled()
  89. }
  90. type Priority int
  91. const (
  92. High Priority = 100
  93. Low Priority = 0
  94. )