Skip to content

Commit 8eea7ed

Browse files
authored
feat: support components to start in dependency order (#1370)
* feat: support components to start in dependency order * imporve * fix * fix error import
1 parent f00b891 commit 8eea7ed

12 files changed

Lines changed: 635 additions & 74 deletions

File tree

pkg/console/component.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ type consoleWebServer struct {
5151
cs consolectx.Context
5252
}
5353

54+
func (c *consoleWebServer) RequiredDependencies() []runtime.ComponentType {
55+
return []runtime.ComponentType{
56+
runtime.ResourceManager, // Console needs Manager for resource operations
57+
// Note: No need to list ResourceStore explicitly as Manager already depends on it
58+
}
59+
}
60+
5461
func (c *consoleWebServer) Type() runtime.ComponentType {
5562
return runtime.Console
5663
}

pkg/console/counter/component.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ type ManagerComponent interface {
3838

3939
var _ ManagerComponent = &managerComponent{}
4040

41+
func (c *managerComponent) RequiredDependencies() []runtime.ComponentType {
42+
return []runtime.ComponentType{
43+
runtime.ResourceStore,
44+
runtime.EventBus, // Counter depends on EventBus to subscribe to events
45+
}
46+
}
47+
4148
type managerComponent struct {
4249
manager CounterManager
4350
}

pkg/core/bootstrap/bootstrap.go

Lines changed: 104 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ package bootstrap
1919

2020
import (
2121
"context"
22+
"fmt"
2223

23-
"github.com/pkg/errors"
24-
24+
"github.com/apache/dubbo-admin/pkg/common/bizerror"
2525
"github.com/apache/dubbo-admin/pkg/config/app"
2626
"github.com/apache/dubbo-admin/pkg/console/counter"
2727
"github.com/apache/dubbo-admin/pkg/core/logger"
@@ -34,106 +34,136 @@ func Bootstrap(appCtx context.Context, cfg app.AdminConfig) (runtime.Runtime, er
3434
if err != nil {
3535
return nil, err
3636
}
37-
// 0. initialize event bus
38-
if err := initEventBus(builder); err != nil {
39-
return nil, err
40-
}
41-
// 1. initialize resource store
42-
if err := initResourceStore(cfg, builder); err != nil {
43-
return nil, err
44-
}
45-
// 2. initialize discovery
46-
if err := initializeResourceDiscovery(builder); err != nil {
47-
return nil, err
48-
}
49-
// 3. initialize engine
50-
if err := initializeResourceEngine(builder); err != nil {
51-
return nil, err
52-
}
53-
// 4. initialize resource manager
54-
if err := initResourceManager(builder); err != nil {
55-
return nil, err
56-
}
57-
// 5. initialize console
58-
if err := initializeConsole(builder); err != nil {
59-
return nil, err
60-
}
61-
// 6. initialize counter manager
62-
if err := initializeCounterManager(builder); err != nil {
37+
38+
// Use smart bootstrapper for intelligent component initialization
39+
bootstrapper := NewSmartBootstrapper(builder)
40+
41+
// Initialize all components in dependency order
42+
if err := bootstrapper.bootstrapComponents(appCtx, cfg); err != nil {
6343
return nil, err
6444
}
65-
// 7. initialize diagnostics
66-
if err := initializeDiagnoticsServer(builder); err != nil {
67-
logger.Errorf("got error when init diagnotics server %s", err)
68-
}
45+
46+
// Build and return runtime
6947
rt, err := builder.Build()
7048
if err != nil {
7149
return nil, err
7250
}
7351
return rt, nil
7452
}
7553

76-
func initEventBus(builder *runtime.Builder) error {
77-
comp, err := runtime.ComponentRegistry().EventBus()
78-
if err != nil {
79-
return err
80-
}
81-
return initAndActivateComponent(builder, comp)
54+
// SmartBootstrapper handles intelligent component initialization
55+
type SmartBootstrapper struct {
56+
builder *runtime.Builder
8257
}
8358

84-
func initResourceStore(cfg app.AdminConfig, builder *runtime.Builder) error {
85-
comp, err := runtime.ComponentRegistry().ResourceStore()
86-
if err != nil {
87-
return errors.Wrapf(err, "could not retrieve resource store %s component", cfg.Store.Type)
59+
// NewSmartBootstrapper creates a new smart bootstrapper
60+
func NewSmartBootstrapper(builder *runtime.Builder) *SmartBootstrapper {
61+
return &SmartBootstrapper{
62+
builder: builder,
8863
}
89-
return initAndActivateComponent(builder, comp)
9064
}
91-
func initResourceManager(builder *runtime.Builder) error {
92-
comp, err := runtime.ComponentRegistry().ResourceManager()
65+
66+
// bootstrapComponents initializes all components in dependency order
67+
func (sb *SmartBootstrapper) bootstrapComponents(
68+
ctx context.Context,
69+
cfg app.AdminConfig,
70+
) error {
71+
logger.Info("Starting smart component bootstrap...")
72+
73+
// Gather all components to initialize
74+
components, err := sb.gatherComponents()
9375
if err != nil {
94-
return err
76+
return bizerror.Wrap(err, bizerror.UnknownError, "failed to gather components")
9577
}
96-
return initAndActivateComponent(builder, comp)
97-
}
9878

99-
func initializeConsole(builder *runtime.Builder) error {
100-
comp, err := runtime.ComponentRegistry().Console()
79+
// Sort components by dependencies
80+
ordered, err := sb.sortComponents(components)
10181
if err != nil {
102-
return err
82+
return bizerror.Wrap(err, bizerror.UnknownError, "failed to sort components by dependencies")
10383
}
104-
return initAndActivateComponent(builder, comp)
105-
}
10684

107-
func initializeResourceDiscovery(builder *runtime.Builder) error {
108-
comp, err := runtime.ComponentRegistry().ResourceDiscovery()
109-
if err != nil {
110-
return err
85+
// Initialize components in order
86+
for i, comp := range ordered {
87+
logger.Infof("[%d/%d] Initializing %s...", i+1, len(ordered), comp.Type())
88+
if err := initAndActivateComponent(sb.builder, comp); err != nil {
89+
return bizerror.Wrap(err, bizerror.UnknownError, fmt.Sprintf("failed to initialize component %s", comp.Type()))
90+
}
91+
logger.Infof("[%d/%d] %s initialized successfully", i+1, len(ordered), comp.Type())
11192
}
112-
return initAndActivateComponent(builder, comp)
93+
94+
logger.Info("All components bootstrapped successfully")
95+
return nil
11396
}
11497

115-
func initializeResourceEngine(builder *runtime.Builder) error {
116-
comp, err := runtime.ComponentRegistry().ResourceEngine()
117-
if err != nil {
118-
return err
98+
// gatherComponents collects all components that need to be initialized
99+
func (sb *SmartBootstrapper) gatherComponents() ([]runtime.Component, error) {
100+
components := []runtime.Component{}
101+
102+
// Core components
103+
coreComps := []struct {
104+
name string
105+
getter func() (runtime.Component, error)
106+
}{
107+
{"EventBus", runtime.ComponentRegistry().EventBus},
108+
{"ResourceStore", runtime.ComponentRegistry().ResourceStore},
109+
{"ResourceDiscovery", runtime.ComponentRegistry().ResourceDiscovery},
110+
{"ResourceEngine", runtime.ComponentRegistry().ResourceEngine},
111+
{"ResourceManager", runtime.ComponentRegistry().ResourceManager},
112+
{"Console", runtime.ComponentRegistry().Console},
119113
}
120-
return initAndActivateComponent(builder, comp)
121-
}
122114

123-
func initializeDiagnoticsServer(builder *runtime.Builder) error {
124-
comp, err := runtime.ComponentRegistry().Get(diagnostics.DiagnosticsServer)
125-
if err != nil {
126-
return err
115+
for _, comp := range coreComps {
116+
c, err := comp.getter()
117+
if err != nil {
118+
return nil, bizerror.Wrap(err, bizerror.UnknownError, fmt.Sprintf("failed to get component %s", comp.name))
119+
}
120+
components = append(components, c)
121+
}
122+
123+
// Optional components
124+
optionalComps := []struct {
125+
name string
126+
typ runtime.ComponentType
127+
}{
128+
{"CounterManager", counter.ComponentType},
129+
{"DiagnosticsServer", diagnostics.DiagnosticsServer},
127130
}
128-
return initAndActivateComponent(builder, comp)
131+
132+
for _, comp := range optionalComps {
133+
c, err := runtime.ComponentRegistry().Get(comp.typ)
134+
if err != nil {
135+
logger.Warnf("Optional component %s not available: %v", comp.name, err)
136+
continue
137+
}
138+
components = append(components, c)
139+
}
140+
141+
return components, nil
129142
}
130143

131-
func initializeCounterManager(builder *runtime.Builder) error {
132-
comp, err := runtime.ComponentRegistry().Get(counter.ComponentType)
144+
// sortComponents sorts components by dependency order
145+
func (sb *SmartBootstrapper) sortComponents(
146+
components []runtime.Component,
147+
) ([]runtime.Component, error) {
148+
// Build dependency graph and perform topological sort
149+
graph := runtime.NewDependencyGraph(components)
150+
sorted, err := graph.TopologicalSort()
133151
if err != nil {
134-
return err
152+
return nil, err
135153
}
136-
return initAndActivateComponent(builder, comp)
154+
155+
// Log initialization order
156+
logger.Info("Component initialization order:")
157+
for i, comp := range sorted {
158+
deps := comp.RequiredDependencies()
159+
if len(deps) > 0 {
160+
logger.Infof(" %d. %s (depends on: %v)", i+1, comp.Type(), deps)
161+
} else {
162+
logger.Infof(" %d. %s (no dependencies)", i+1, comp.Type())
163+
}
164+
}
165+
166+
return sorted, nil
137167
}
138168

139169
func initAndActivateComponent(builder *runtime.Builder, comp runtime.Component) error {
@@ -143,7 +173,7 @@ func initAndActivateComponent(builder *runtime.Builder, comp runtime.Component)
143173
}
144174
logger.Infof("%s initialized successfully", comp.Type())
145175
if err := builder.ActivateComponent(comp); err != nil {
146-
return errors.Wrapf(err, "failed to activate %s", comp.Type())
176+
return bizerror.Wrap(err, bizerror.UnknownError, fmt.Sprintf("failed to activate %s", comp.Type()))
147177
}
148178
return nil
149179
}

pkg/core/discovery/component.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ type discoveryComponent struct {
5757
subscriptionMgr events.SubscriptionManager
5858
}
5959

60+
func (d *discoveryComponent) RequiredDependencies() []runtime.ComponentType {
61+
return []runtime.ComponentType{
62+
runtime.EventBus, // Discovery needs EventBus for event emission
63+
runtime.ResourceStore, // Discovery needs Store for resource storage
64+
}
65+
}
66+
6067
func newDiscoveryComponent() Component {
6168
return &discoveryComponent{
6269
informers: make(map[string]Informers),

pkg/core/engine/component.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ func newEngineComponent() Component {
6060
subscribers: make([]events.Subscriber, 0),
6161
}
6262
}
63+
64+
func (e *engineComponent) RequiredDependencies() []runtime.ComponentType {
65+
return []runtime.ComponentType{
66+
runtime.EventBus,
67+
runtime.ResourceStore,
68+
}
69+
}
70+
6371
func (e *engineComponent) Type() runtime.ComponentType {
6472
return runtime.ResourceEngine
6573
}

pkg/core/events/component.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ type eventBus struct {
4343
subscriberDir map[model.ResourceKind]Subscribers
4444
}
4545

46+
func (b *eventBus) RequiredDependencies() []runtime.ComponentType {
47+
return []runtime.ComponentType{} // EventBus has no dependencies
48+
}
49+
4650
func (b *eventBus) Type() runtime.ComponentType {
4751
return runtime.EventBus
4852
}

pkg/core/manager/component.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ type resourceManagerComponent struct {
4141
rm ResourceManager
4242
}
4343

44+
func (r *resourceManagerComponent) RequiredDependencies() []runtime.ComponentType {
45+
return []runtime.ComponentType{
46+
runtime.ResourceStore, // Manager needs Store to be initialized first
47+
}
48+
}
49+
4450
func (r *resourceManagerComponent) Type() runtime.ComponentType {
4551
return runtime.ResourceManager
4652
}

pkg/core/runtime/component.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ type Attribute interface {
4242
// Type returns the type of the component
4343
Type() ComponentType
4444
// Order indicates the order of the component during bootstrap, the bigger will be started first
45+
// Deprecated: Use RequiredDependencies() instead for explicit dependency management
4546
Order() int
47+
// RequiredDependencies returns the component types that must be initialized before this component
48+
// The system will ensure all required dependencies are initialized first, or fail with a clear error
49+
// Return an empty slice if the component has no dependencies
50+
RequiredDependencies() []ComponentType
4651
}
4752

4853
// Component defines a process that will be run in the application

0 commit comments

Comments
 (0)