refactor(config): improve concurrency in route providers loading

- Replaced synchronous error handling with concurrent processing for loading providers.
- Removed the errIfExists function and integrated its logic into the provider loading process.
- Enhanced error reporting for existing providers and agent startup failures.
- Streamlined the use of wait groups for better management of concurrent tasks.
This commit is contained in:
yusing
2025-09-05 11:34:01 +08:00
parent 97b6066466
commit 3e43f7d27f

View File

@@ -322,48 +322,36 @@ func (cfg *Config) initProxmox(proxmoxCfg []proxmox.Config) gperr.Error {
return errs.Error() return errs.Error()
} }
func (cfg *Config) errIfExists(p *proxy.Provider) gperr.Error {
if _, ok := cfg.providers.Load(p.String()); ok {
return gperr.Errorf("provider %s already exists", p.String())
}
return nil
}
func (cfg *Config) storeProvider(p *proxy.Provider) { func (cfg *Config) storeProvider(p *proxy.Provider) {
cfg.providers.Store(p.String(), p) cfg.providers.Store(p.String(), p)
} }
func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error { func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error {
errs := gperr.NewBuilder("route provider errors") errs := gperr.NewBuilderWithConcurrency("route provider errors")
results := gperr.NewBuilder("loaded route providers") results := gperr.NewBuilder("loaded route providers")
agentPkg.RemoveAllAgents() agentPkg.RemoveAllAgents()
numProviders := len(providers.Agents) + len(providers.Files) + len(providers.Docker) numProviders := len(providers.Agents) + len(providers.Files) + len(providers.Docker)
providersCh := make(chan *proxy.Provider, numProviders) providersCh := make(chan *proxy.Provider, numProviders)
errsCh := make(chan error, numProviders)
var goRoutines sync.WaitGroup // start providers concurrently
goRoutines.Go(func() { var providersConsumer sync.WaitGroup
providersConsumer.Go(func() {
for p := range providersCh { for p := range providersCh {
if err := cfg.errIfExists(p); err != nil { if actual, loaded := cfg.providers.LoadOrStore(p.String(), p); loaded {
errs.Add(err.Subject(p.String())) errs.Add(gperr.Errorf("provider %s already exists, first: %s, second: %s", p.String(), actual.GetType(), p.GetType()))
continue continue
} }
cfg.storeProvider(p) cfg.storeProvider(p)
} }
}) })
goRoutines.Go(func() {
for err := range errsCh {
errs.Add(err)
}
})
var providersWg sync.WaitGroup var providersProducer sync.WaitGroup
for _, agent := range providers.Agents { for _, agent := range providers.Agents {
providersWg.Go(func() { providersProducer.Go(func() {
if err := agent.Start(cfg.task.Context()); err != nil { if err := agent.Start(cfg.task.Context()); err != nil {
errsCh <- gperr.PrependSubject(agent.String(), err) errs.Add(gperr.PrependSubject(agent.String(), err))
return return
} }
agentPkg.AddAgent(agent) agentPkg.AddAgent(agent)
@@ -373,10 +361,10 @@ func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error {
} }
for _, filename := range providers.Files { for _, filename := range providers.Files {
providersWg.Go(func() { providersProducer.Go(func() {
p, err := proxy.NewFileProvider(filename) p, err := proxy.NewFileProvider(filename)
if err != nil { if err != nil {
errsCh <- gperr.PrependSubject(filename, err) errs.Add(gperr.PrependSubject(filename, err))
} else { } else {
providersCh <- p providersCh <- p
} }
@@ -384,18 +372,15 @@ func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error {
} }
for name, dockerHost := range providers.Docker { for name, dockerHost := range providers.Docker {
providersWg.Go(func() { providersProducer.Go(func() {
providersCh <- proxy.NewDockerProvider(name, dockerHost) providersCh <- proxy.NewDockerProvider(name, dockerHost)
}) })
} }
providersWg.Wait() providersProducer.Wait()
if cfg.providers.Size() == 0 { close(providersCh)
close(providersCh) providersConsumer.Wait()
close(errsCh)
return errs.Error()
}
lenLongestName := 0 lenLongestName := 0
for k := range cfg.providers.Range { for k := range cfg.providers.Range {
@@ -406,21 +391,18 @@ func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error {
results.EnableConcurrency() results.EnableConcurrency()
providersWg = sync.WaitGroup{} // load routes concurrently
var providersLoader sync.WaitGroup
for _, p := range cfg.providers.Range { for _, p := range cfg.providers.Range {
providersWg.Go(func() { providersLoader.Go(func() {
if err := p.LoadRoutes(); err != nil { if err := p.LoadRoutes(); err != nil {
errsCh <- err.Subject(p.String()) errs.Add(err.Subject(p.String()))
} }
results.Addf("%-"+strconv.Itoa(lenLongestName)+"s %d routes", p.String(), p.NumRoutes()) results.Addf("%-"+strconv.Itoa(lenLongestName)+"s %d routes", p.String(), p.NumRoutes())
}) })
} }
providersWg.Wait() providersLoader.Wait()
log.Info().Msg(results.String()) log.Info().Msg(results.String())
close(providersCh)
close(errsCh)
goRoutines.Wait()
return errs.Error() return errs.Error()
} }