Skip to content

Commit 05e7a36

Browse files
committed
Retry config sync on concurrent changes
1 parent 74c095d commit 05e7a36

5 files changed

Lines changed: 610 additions & 128 deletions

File tree

docs/development/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,12 @@ description: Developer documentation for Thand Agent
99
# Development
1010

1111
Documentation for developers contributing to or extending the Thand Agent.
12+
13+
## Config Mutation Invariant
14+
15+
Configuration definition maps should be treated as immutable snapshots.
16+
When config changes, prefer replacing whole entries or whole definition maps
17+
instead of mutating nested state in place. Some older code paths still perform
18+
mutation-prone updates; keep new code aligned with the invariant and track
19+
cleanup of legacy exceptions in follow-up issues rather than extending them.
20+
Current cleanup work is tracked in [#306](https://github.com/thand-io/agent/issues/306).

internal/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ func (c *Config) ReloadConfig() error {
358358
logrus.Infoln("Loaded workflows from external source:", len(workflows))
359359
c.mu.Lock()
360360
c.Workflows.Definitions = workflows
361+
c.configGeneration++
361362
c.mu.Unlock()
362363
} else {
363364
logrus.Warningln("No workflows loaded from external source")
@@ -376,6 +377,7 @@ func (c *Config) ReloadConfig() error {
376377
logrus.Infoln("Loaded providers from external source:", len(providers))
377378
c.mu.Lock()
378379
c.Providers.Definitions = providers
380+
c.configGeneration++
379381
c.mu.Unlock()
380382
} else {
381383
logrus.Warningln("No providers loaded from external source")
@@ -392,6 +394,7 @@ func (c *Config) ReloadConfig() error {
392394
logrus.Infoln("Loaded roles from external source:", len(roles))
393395
c.mu.Lock()
394396
c.Roles.Definitions = roles
397+
c.configGeneration++
395398
c.mu.Unlock()
396399
} else {
397400
logrus.Warningln("No roles loaded from external source")

internal/config/model.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ type Config struct {
6464
logger thandLogger
6565
mu sync.RWMutex
6666

67+
// Incremented whenever synced config definitions actually change.
68+
// Definition maps should be treated as immutable snapshots: callers should
69+
// replace whole entries or whole maps rather than mutating nested state
70+
// in place. Legacy mutation-prone paths are being tracked in issue #306.
71+
configGeneration uint64
72+
6773
// Cached services client
6874
initializeServiceClientOnce sync.Once
6975
servicesClient models.ServicesClientImpl

0 commit comments

Comments
 (0)