Files
navidrome/plugins/plugin_lifecycle_manager.go
Deluan Quintão d041cb3249
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push Docker manifest (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
fix(plugins): correct error handling in plugin initialization (#4311)
Updated the error handling logic in the plugin lifecycle manager to accurately record the success of the OnInit method. The change ensures that the metrics reflect whether the initialization was successful, improving the reliability of plugin metrics tracking. Additionally, removed the unused errorMapper interface from base_capability.go to clean up the codebase.

Signed-off-by: Deluan <deluan@navidrome.org>
2025-07-07 16:24:10 -03:00

96 lines
3.1 KiB
Go

package plugins
import (
"context"
"maps"
"sync"
"time"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/core/metrics"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/plugins/api"
)
// pluginLifecycleManager tracks which plugins have been initialized and manages their lifecycle
type pluginLifecycleManager struct {
plugins sync.Map // string -> bool
config map[string]map[string]string
metrics metrics.Metrics
}
// newPluginLifecycleManager creates a new plugin lifecycle manager
func newPluginLifecycleManager(metrics metrics.Metrics) *pluginLifecycleManager {
config := maps.Clone(conf.Server.PluginConfig)
return &pluginLifecycleManager{
config: config,
metrics: metrics,
}
}
// isInitialized checks if a plugin has been initialized
func (m *pluginLifecycleManager) isInitialized(plugin *plugin) bool {
key := plugin.ID + consts.Zwsp + plugin.Manifest.Version
value, exists := m.plugins.Load(key)
return exists && value.(bool)
}
// markInitialized marks a plugin as initialized
func (m *pluginLifecycleManager) markInitialized(plugin *plugin) {
key := plugin.ID + consts.Zwsp + plugin.Manifest.Version
m.plugins.Store(key, true)
}
// clearInitialized removes the initialization state of a plugin
func (m *pluginLifecycleManager) clearInitialized(plugin *plugin) {
key := plugin.ID + consts.Zwsp + plugin.Manifest.Version
m.plugins.Delete(key)
}
// callOnInit calls the OnInit method on a plugin that implements LifecycleManagement
func (m *pluginLifecycleManager) callOnInit(plugin *plugin) error {
ctx := context.Background()
log.Debug("Initializing plugin", "name", plugin.ID)
start := time.Now()
// Create LifecycleManagement plugin instance
loader, err := api.NewLifecycleManagementPlugin(ctx, api.WazeroRuntime(plugin.Runtime), api.WazeroModuleConfig(plugin.ModConfig))
if loader == nil || err != nil {
log.Error("Error creating LifecycleManagement plugin", "plugin", plugin.ID, err)
return err
}
initPlugin, err := loader.Load(ctx, plugin.WasmPath)
if err != nil {
log.Error("Error loading LifecycleManagement plugin", "plugin", plugin.ID, "path", plugin.WasmPath, err)
return err
}
defer initPlugin.Close(ctx)
// Prepare the request with plugin-specific configuration
req := &api.InitRequest{}
// Add plugin configuration if available
if m.config != nil {
if pluginConfig, ok := m.config[plugin.ID]; ok && len(pluginConfig) > 0 {
req.Config = maps.Clone(pluginConfig)
log.Debug("Passing configuration to plugin", "plugin", plugin.ID, "configKeys", len(pluginConfig))
}
}
// Call OnInit
callStart := time.Now()
_, err = checkErr(initPlugin.OnInit(ctx, req))
m.metrics.RecordPluginRequest(ctx, plugin.ID, "OnInit", err == nil, time.Since(callStart).Milliseconds())
if err != nil {
log.Error("Error initializing plugin", "plugin", plugin.ID, "elapsed", time.Since(start), err)
return err
}
// Mark the plugin as initialized
m.markInitialized(plugin)
log.Debug("Plugin initialized successfully", "plugin", plugin.ID, "elapsed", time.Since(start))
return nil
}