in src/ulsp/controller/ulsp-daemon/ulsp_daemon.go [214:264]
func (c *controller) executePluginMethods(ctx context.Context, method string, handlerSync func(ctx context.Context, m *ulspplugin.Methods), handlerAsync func(ctx context.Context, m *ulspplugin.Methods)) error {
if handlerSync == nil || handlerAsync == nil {
return fmt.Errorf("handlers cannot be nil")
}
id, err := mapper.ContextToSessionUUID(ctx)
if err != nil {
return fmt.Errorf("getting session from context: %w", err)
}
if _, ok := c.pluginMethods[id]; !ok {
return nil
}
methodLists, ok := c.pluginMethods[id][method]
if !ok {
// No need to execute if this method has no registered plugins.
return nil
}
for _, current := range methodLists.Sync {
handlerSync(ctx, current)
}
// Outer goroutine will spawn a goroutine for each asynchronous plugin method, then wait for them to complete with a timeout.
// Plugins that implement asynchronous methods are responsible for respecting the context timeout or cancellation signal.
c.wg.Add(1)
go func() {
defer c.wg.Done()
// New context with its own timeout for asynchronous calls.
asyncCtx := context.WithValue(context.Background(), entity.SessionContextKey, ctx.Value(entity.SessionContextKey))
asyncCtx, cancel := context.WithTimeout(asyncCtx, _contextTimeoutSecondsAsync*time.Second)
defer cancel()
// Spawn a separate goroutine for each method's context, then wait for them all to complete.
var innerWg sync.WaitGroup
for _, current := range methodLists.Async {
currentMethods := current
innerWg.Add(1)
go func() {
defer innerWg.Done()
handlerAsync(asyncCtx, currentMethods)
}()
}
innerWg.Wait()
}()
return nil
}