Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: register reloadable config variables #108

Merged
merged 38 commits into from
Sep 13, 2023
Merged

Conversation

fracasula
Copy link
Collaborator

@fracasula fracasula commented Aug 30, 2023

Description

Now that we're running warehouse tests with the -race flags (used in order to prevent races to go to production), we're seeing random failures in some tests (e.g. snowflake integrations) with hot-reloadable configs.

This PR tries to address the issue in a backwards compatible manner and by providing a succint alternative to use the new API without having to burden ourselves with locking and unlocking mutexes each time we have to deal with such variables.

Context

==================
WARNING: DATA RACE
Write at 0x000008f21110 by goroutine 3191:
  github.com/rudderlabs/rudder-go-kit/config.(*Config).RegisterDurationConfigVariable()
      /home/francesco/go/pkg/mod/github.com/rudderlabs/rudder-go-kit@v0.15.7/config/hotreloadable.go:159 +0x66f
  github.com/rudderlabs/rudder-go-kit/config.RegisterDurationConfigVariable()
      /home/francesco/go/pkg/mod/github.com/rudderlabs/rudder-go-kit@v0.15.7/config/hotreloadable.go:133 +0x467
  github.com/rudderlabs/rudder-server/services/pgnotifier.loadPGNotifierConfig()
      /home/francesco/Code/rudderstack/rudder-server/services/pgnotifier/pgnotifier.go:113 +0x3df
  github.com/rudderlabs/rudder-server/services/pgnotifier.Init()
      /home/francesco/Code/rudderstack/rudder-server/services/pgnotifier/pgnotifier.go:55 +0x29
  github.com/rudderlabs/rudder-server/runner.runAllInit()
      /home/francesco/Code/rudderstack/rudder-server/runner/runner.go:331 +0xb3
  github.com/rudderlabs/rudder-server/runner.(*Runner).Run()
      /home/francesco/Code/rudderstack/rudder-server/runner/runner.go:151 +0x100a
  github.com/rudderlabs/rudder-server/warehouse/integrations/snowflake_test.TestIntegration.func1.1()
      /home/francesco/Code/rudderstack/rudder-server/warehouse/integrations/snowflake/snowflake_test.go:189 +0xee

Previous read at 0x000008f21110 by goroutine 258:
  github.com/rudderlabs/rudder-server/services/pgnotifier.(*PGNotifier).Subscribe.func1()
      /home/francesco/Code/rudderstack/rudder-server/services/pgnotifier/pgnotifier.go:616 +0x1e9
  github.com/rudderlabs/rudder-server/rruntime.GoForWarehouse.func1()
      /home/francesco/Code/rudderstack/rudder-server/rruntime/goroutine-factory.go:36 +0x77

Goroutine 3191 (running) created at:
  github.com/rudderlabs/rudder-server/warehouse/integrations/snowflake_test.TestIntegration.func1()
      /home/francesco/Code/rudderstack/rudder-server/warehouse/integrations/snowflake/snowflake_test.go:187 +0x364
  github.com/rudderlabs/rudder-server/warehouse/integrations/snowflake_test.TestIntegration.func2.1()
      /home/francesco/Code/rudderstack/rudder-server/warehouse/integrations/snowflake/snowflake_test.go:332 +0xec
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1576 +0x216
  testing.(*T).Run.func1()
      /usr/local/go/src/testing/testing.go:1629 +0x47

Linear Ticket

< Linear Link >

Security

  • The code changed/added as part of this pull request won't create any security issues with how the software is being used.

@fracasula fracasula changed the title fix: register atomic int fix: register atomic variables Aug 30, 2023
@fracasula fracasula changed the title fix: register atomic variables fix: register atomic config variables Aug 30, 2023
@codecov
Copy link

codecov bot commented Aug 30, 2023

Codecov Report

Patch coverage: 85.49% and project coverage change: +0.66% 🎉

Comparison is base (ff2dc63) 78.70% compared to head (6e01bd3) 79.37%.
Report is 1 commits behind head on main.

❗ Current head 6e01bd3 differs from pull request most recent head 562b3e7. Consider uploading reports for the commit 562b3e7 to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #108      +/-   ##
==========================================
+ Coverage   78.70%   79.37%   +0.66%     
==========================================
  Files          68       68              
  Lines        4866     5087     +221     
==========================================
+ Hits         3830     4038     +208     
- Misses        830      849      +19     
+ Partials      206      200       -6     
Files Changed Coverage Δ
logger/config.go 91.89% <ø> (ø)
config/hotreloadable.go 87.62% <81.88%> (+5.71%) ⬆️
config/config.go 82.60% <100.00%> (+2.86%) ⬆️
config/load.go 92.26% <100.00%> (+0.32%) ⬆️
logger/factory.go 80.37% <100.00%> (ø)
logger/logger.go 97.39% <100.00%> (ø)

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

config/hotreloadable.go Outdated Show resolved Hide resolved
@Sidddddarth
Copy link
Member

I haven't implemented this for all methods yet, I'd like to receive some early feedback if possible.

LGTM

@fracasula fracasula marked this pull request as ready for review August 31, 2023 16:59
@atzoum
Copy link
Collaborator

atzoum commented Aug 31, 2023

One major issue we are having now with the RegisterXxx API is that the config package keeps pointers to fields of other structs, e.g. router, batchrouter, jobsdb handes etc. so these structs are never garbage collected even though they might no longer be needed by the system (see MT rudder server stop/start sequences). So we end up with a slow-burning memory leak.
Can we invert the control and let the config package return pointers to configuration variables instead?
Furthermore, asking for the same reloadable configuration property twice shouldn't result in multiple atomic structs to be created, the existing struct could be reused.
Finally, the Atomic struct could only export a Load method and keep Store unexported

@fracasula
Copy link
Collaborator Author

@atzoum I wasn't aware of the memory leaks, I'll have a look 👍

config/config.go Outdated Show resolved Hide resolved
config/hotreloadable.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@atzoum atzoum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you @fracasula for taking the extra time to try and address important issues with our reloadable configs!

config/config.go Outdated Show resolved Hide resolved
// RegisterAtomicIntVar registers a hot-reloadable int config variable
// Copy of RegisterIntConfigVariable, but with a way to avoid data races for hot reloadable config variables
func (c *Config) RegisterAtomicIntVar(defaultValue, valueScale int, keys ...string) *Atomic[int] {
ptr := getOrCreatePointer(c.atomicVars, c.atomicVarsMisuses, &c.atomicVarsLock, defaultValue, keys...)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever we are reusing an existing pointer we shouldn't register it again.
If getOrCreatePointer returned a second value indicating whether this is a new or existing pointer, we could use this information for avoiding registering it twice.

One thing we should definitely fix though is whenever we are calling appendVarToConfigMaps, we should pass as a key the full concatenated key instead of the first key from the slice.

Copy link
Collaborator Author

@fracasula fracasula Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing we should definitely fix though is whenever we are calling appendVarToConfigMaps, we should pass as a key the full concatenated key instead of the first key from the slice.

Nice, good catch 👍

Whenever we are reusing an existing pointer we shouldn't register it again. If getOrCreatePointer returned a second value indicating whether this is a new or existing pointer, we could use this information for avoiding registering it twice.

We could allow this though, it is now safe to do so and you'll get the same variable. I'm keen to let people do it at this point. If someone misuses the default values will get a panic as well. Perhaps we should settle on the discussion about the order of the keys first, I might be missing some use case.

config/config.go Outdated
Comment on lines 84 to 86
atomicVars map[string]any
atomicVarsMisuses map[string]string
atomicVarsLock sync.RWMutex // used to protect both atomicVars maps
Copy link
Collaborator

@atzoum atzoum Sep 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: since all these fields are part of the hot-reloadable feature we could use hotReloadableConfigLock instead of atomicVarsLock, is there an actual need for a second lock?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are used at different times and to protect different data so I'm keen to keep both actually to minimize lock contention. It seems like a small price to pay.

config/hotreloadable.go Outdated Show resolved Hide resolved
config/hotreloadable.go Show resolved Hide resolved
config/hotreloadable.go Outdated Show resolved Hide resolved
config/hotreloadable.go Outdated Show resolved Hide resolved
config/hotreloadable.go Outdated Show resolved Hide resolved
config/hotreloadable.go Outdated Show resolved Hide resolved
@fracasula fracasula changed the title fix: register atomic config variables fix: register reloadable config variables Sep 12, 2023
@fracasula fracasula merged commit 2466840 into main Sep 13, 2023
8 checks passed
@fracasula fracasula deleted the fix.configHotReload branch September 13, 2023 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants