From e19625793676e473e0a775eb6ecfdb0139fac009 Mon Sep 17 00:00:00 2001 From: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:29:05 -0400 Subject: [PATCH 1/4] add tracking and comparison of latest healthy content before loading a module Signed-off-by: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> --- component/module/module.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/component/module/module.go b/component/module/module.go index 2456269647c3..7baeab5597a2 100644 --- a/component/module/module.go +++ b/component/module/module.go @@ -14,8 +14,9 @@ type ModuleComponent struct { opts component.Options mod component.Module - mut sync.RWMutex - health component.Health + mut sync.RWMutex + health component.Health + latestContent string } // Exports holds values which are exported from the run module. @@ -38,10 +39,16 @@ func NewModuleComponent(o component.Options) (*ModuleComponent, error) { // LoadFlowContent loads the flow controller with the current component content. It // will set the component health in addition to return the error so that the consumer -// can rely on either or both. +// can rely on either or both. If the content is the same as the last time it was +// successfully loaded, it will not be reloaded. func (c *ModuleComponent) LoadFlowContent(args map[string]any, contentValue string) error { + if contentValue == c.getLatestContent() { + return nil + } + err := c.mod.LoadConfig([]byte(contentValue), args) if err != nil { + c.setLatestContent("") c.setHealth(component.Health{ Health: component.HealthTypeUnhealthy, Message: fmt.Sprintf("failed to load module content: %s", err), @@ -51,11 +58,13 @@ func (c *ModuleComponent) LoadFlowContent(args map[string]any, contentValue stri return err } + c.setLatestContent(contentValue) c.setHealth(component.Health{ Health: component.HealthTypeHealthy, Message: "module content loaded", UpdateTime: time.Now(), }) + return nil } @@ -77,3 +86,15 @@ func (c *ModuleComponent) setHealth(h component.Health) { defer c.mut.Unlock() c.health = h } + +func (c *ModuleComponent) setLatestContent(content string) { + c.mut.Lock() + defer c.mut.Unlock() + c.latestContent = content +} + +func (c *ModuleComponent) getLatestContent() string { + c.mut.RLock() + defer c.mut.RUnlock() + return c.latestContent +} From 3b93e23d226e0a2b28a6bc447d3838ff609673a3 Mon Sep 17 00:00:00 2001 From: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:35:49 -0400 Subject: [PATCH 2/4] changelog Signed-off-by: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 139fc6068baa..cd7746716ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,12 @@ Main (unreleased) - Read contextual attributes from Faro measurements (@codecapitano) - Rename Grafana Agent service in windows app and features to not include the description +### Bugfixes + +- Restart managed components of a module loader only on if module content + changes or the last load failed. This was specifically impacting `module.git` + each time it pulls. (@erikbaranowski) + v0.36.0 (2023-08-30) -------------------- From 44b523d9eb28f837c178f9e445a8319b2c334762 Mon Sep 17 00:00:00 2001 From: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:49:07 -0400 Subject: [PATCH 3/4] don't reset latestContent or set it at all on failure to load module Signed-off-by: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> --- component/module/module.go | 1 - 1 file changed, 1 deletion(-) diff --git a/component/module/module.go b/component/module/module.go index 7baeab5597a2..03ffc101f66d 100644 --- a/component/module/module.go +++ b/component/module/module.go @@ -48,7 +48,6 @@ func (c *ModuleComponent) LoadFlowContent(args map[string]any, contentValue stri err := c.mod.LoadConfig([]byte(contentValue), args) if err != nil { - c.setLatestContent("") c.setHealth(component.Health{ Health: component.HealthTypeUnhealthy, Message: fmt.Sprintf("failed to load module content: %s", err), From e186f5fc250fb9a4ac9e7131e418ecdd67b6883a Mon Sep 17 00:00:00 2001 From: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:04:42 -0400 Subject: [PATCH 4/4] add tracking and check for arguments in module loaders Signed-off-by: erikbaranowski <39704712+erikbaranowski@users.noreply.github.com> --- component/module/module.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/component/module/module.go b/component/module/module.go index 03ffc101f66d..9e03e6d9213c 100644 --- a/component/module/module.go +++ b/component/module/module.go @@ -3,6 +3,7 @@ package module import ( "context" "fmt" + "reflect" "sync" "time" @@ -17,6 +18,7 @@ type ModuleComponent struct { mut sync.RWMutex health component.Health latestContent string + latestArgs map[string]any } // Exports holds values which are exported from the run module. @@ -42,7 +44,7 @@ func NewModuleComponent(o component.Options) (*ModuleComponent, error) { // can rely on either or both. If the content is the same as the last time it was // successfully loaded, it will not be reloaded. func (c *ModuleComponent) LoadFlowContent(args map[string]any, contentValue string) error { - if contentValue == c.getLatestContent() { + if reflect.DeepEqual(args, c.getLatestArgs()) && contentValue == c.getLatestContent() { return nil } @@ -57,6 +59,7 @@ func (c *ModuleComponent) LoadFlowContent(args map[string]any, contentValue stri return err } + c.setLatestArgs(args) c.setLatestContent(contentValue) c.setHealth(component.Health{ Health: component.HealthTypeHealthy, @@ -97,3 +100,19 @@ func (c *ModuleComponent) getLatestContent() string { defer c.mut.RUnlock() return c.latestContent } + +func (c *ModuleComponent) setLatestArgs(args map[string]any) { + c.mut.Lock() + defer c.mut.Unlock() + + c.latestArgs = make(map[string]any) + for key, value := range args { + c.latestArgs[key] = value + } +} + +func (c *ModuleComponent) getLatestArgs() map[string]any { + c.mut.RLock() + defer c.mut.RUnlock() + return c.latestArgs +}