Skip to content

Commit c781996

Browse files
chore(main): start services in the order they are registered (#2683)
### Proposed Changes * Preserve the order of registered services so we start and stop them in a given order each time. ### Checklist - [ ] I have added or updated unit tests - [ ] I have added or updated integration tests (if appropriate) - [ ] I have added or updated documentation ### Testing Instructions
1 parent c194e35 commit c781996

File tree

2 files changed

+59
-32
lines changed

2 files changed

+59
-32
lines changed

service/pkg/server/services.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const (
4646

4747
// registerEssentialServices registers the essential services to the given service registry.
4848
// It takes a serviceregistry.Registry as input and returns an error if registration fails.
49-
func registerEssentialServices(reg serviceregistry.Registry) error {
49+
func registerEssentialServices(reg *serviceregistry.Registry) error {
5050
essentialServices := []serviceregistry.IService{
5151
health.NewRegistration(),
5252
}
@@ -61,7 +61,7 @@ func registerEssentialServices(reg serviceregistry.Registry) error {
6161

6262
// registerCoreServices registers the core services based on the provided mode.
6363
// It returns the list of registered services and any error encountered during registration.
64-
func registerCoreServices(reg serviceregistry.Registry, mode []string) ([]string, error) {
64+
func registerCoreServices(reg *serviceregistry.Registry, mode []string) ([]string, error) {
6565
var (
6666
services []serviceregistry.IService
6767
registeredServices []string
@@ -123,7 +123,7 @@ type startServicesParams struct {
123123
otdf *server.OpenTDFServer
124124
client *sdk.SDK
125125
logger *logging.Logger
126-
reg serviceregistry.Registry
126+
reg *serviceregistry.Registry
127127
cacheManager *cache.Manager
128128
keyManagerFactories []trust.NamedKeyManagerFactory
129129
}
@@ -143,8 +143,12 @@ func startServices(ctx context.Context, params startServicesParams) (func(), err
143143
cacheManager := params.cacheManager
144144
keyManagerFactories := params.keyManagerFactories
145145

146-
// Iterate through the registered namespaces
147-
for ns, namespace := range reg {
146+
for _, ns := range reg.GetNamespaces() {
147+
namespace, err := reg.GetNamespace(ns)
148+
if err != nil {
149+
// This is an internal inconsistency and should not happen.
150+
return nil, fmt.Errorf("namespace not found: %w", err)
151+
}
148152
// modeEnabled checks if the mode is enabled based on the configuration and namespace mode.
149153
// It returns true if the mode is "all" or "essential" in the configuration, or if it matches the namespace mode.
150154
modeEnabled := slices.ContainsFunc(cfg.Mode, func(m string) bool {

service/pkg/serviceregistry/serviceregistry.go

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -237,18 +237,24 @@ type Namespace struct {
237237
Services []IService
238238
}
239239

240-
// Registry represents a map of service namespaces.
241-
type Registry map[string]Namespace
240+
// Registry is a collection of services, organized by namespace, that preserves registration order.
241+
type Registry struct {
242+
namespaces map[string]*Namespace
243+
order []string
244+
}
242245

243246
// NewServiceRegistry creates a new instance of the service registry.
244-
func NewServiceRegistry() Registry {
245-
return make(Registry)
247+
func NewServiceRegistry() *Registry {
248+
return &Registry{
249+
namespaces: make(map[string]*Namespace),
250+
order: make([]string, 0),
251+
}
246252
}
247253

248254
// RegisterCoreService registers a core service with the given registration information.
249255
// It calls the RegisterService method of the Registry instance with the provided registration and service type "core".
250256
// Returns an error if the registration fails.
251-
func (reg Registry) RegisterCoreService(svc IService) error {
257+
func (reg *Registry) RegisterCoreService(svc IService) error {
252258
return reg.RegisterService(svc, "core")
253259
}
254260

@@ -258,39 +264,48 @@ func (reg Registry) RegisterCoreService(svc IService) error {
258264
// such as the namespace and service description.
259265
// The mode string specifies the mode in which the service should be registered.
260266
// It returns an error if the service is already registered in the specified namespace.
261-
func (reg Registry) RegisterService(svc IService, mode string) error {
262-
// Can't directly modify structs within a map, so we need to copy the namespace
263-
copyNamespace := reg[svc.GetNamespace()]
264-
copyNamespace.Mode = mode
265-
if copyNamespace.Services == nil {
266-
copyNamespace.Services = make([]IService, 0)
267+
func (reg *Registry) RegisterService(svc IService, mode string) error {
268+
nsName := svc.GetNamespace()
269+
ns, _ := reg.GetNamespace(nsName)
270+
271+
if ns == nil {
272+
ns = &Namespace{
273+
Mode: mode,
274+
Services: make([]IService, 0),
275+
}
276+
reg.namespaces[nsName] = ns
277+
reg.order = append(reg.order, nsName)
267278
}
268-
found := slices.ContainsFunc(reg[svc.GetNamespace()].Services, func(s IService) bool {
279+
280+
// Check if a service with the same name is already registered in this namespace.
281+
found := slices.ContainsFunc(ns.Services, func(s IService) bool {
269282
return s.GetServiceDesc().ServiceName == svc.GetServiceDesc().ServiceName
270283
})
271-
272284
if found {
273-
return fmt.Errorf("service already registered namespace:%s service:%s", svc.GetNamespace(), svc.GetServiceDesc().ServiceName)
285+
return fmt.Errorf("service already registered namespace:%s service:%s", nsName, svc.GetServiceDesc().ServiceName)
274286
}
275287

276288
slog.Info(
277289
"registered service",
278-
slog.String("namespace", svc.GetNamespace()),
290+
slog.String("namespace", nsName),
279291
slog.String("service", svc.GetServiceDesc().ServiceName),
280292
)
281-
copyNamespace.Services = append(copyNamespace.Services, svc)
282293

283-
reg[svc.GetNamespace()] = copyNamespace
294+
ns.Mode = mode
295+
ns.Services = append(ns.Services, svc)
296+
reg.namespaces[nsName] = ns
297+
284298
return nil
285299
}
286300

287-
// Shutdown stops all the services in the service registry.
288-
// It iterates over each namespace and service in the registry,
289-
// checks if the service has a Close method and if it has been started,
290-
// and then calls the Close method to stop the service.
291-
func (reg Registry) Shutdown() {
292-
for name, ns := range reg {
293-
for _, svc := range ns.Services {
301+
// Shutdown stops all the registered services in the reverse order of registration.
302+
// If a service is started and has a Close method, the Close method will be called.
303+
func (reg *Registry) Shutdown() {
304+
for nsIdx := len(reg.order) - 1; nsIdx >= 0; nsIdx-- {
305+
name := reg.order[nsIdx]
306+
ns := reg.namespaces[name]
307+
for serviceIdx := len(ns.Services) - 1; serviceIdx >= 0; serviceIdx-- {
308+
svc := ns.Services[serviceIdx]
294309
if svc.IsStarted() {
295310
slog.Info("stopping service",
296311
slog.String("namespace", name),
@@ -309,10 +324,18 @@ func (reg Registry) Shutdown() {
309324
}
310325

311326
// GetNamespace returns the namespace with the given name from the service registry.
312-
func (reg Registry) GetNamespace(namespace string) (Namespace, error) {
313-
ns, ok := reg[namespace]
327+
func (reg *Registry) GetNamespace(namespace string) (*Namespace, error) {
328+
ns, ok := reg.namespaces[namespace]
314329
if !ok {
315-
return Namespace{}, fmt.Errorf("namespace not found: %s", namespace)
330+
return nil, fmt.Errorf("namespace not found: %s", namespace)
316331
}
317332
return ns, nil
318333
}
334+
335+
// GetNamespaces returns the names of the namespaces in the order they were registered.
336+
func (reg *Registry) GetNamespaces() []string {
337+
// Return a copy to prevent modification of the internal order slice.
338+
orderCopy := make([]string, len(reg.order))
339+
copy(orderCopy, reg.order)
340+
return orderCopy
341+
}

0 commit comments

Comments
 (0)