-
Notifications
You must be signed in to change notification settings - Fork 373
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
feat: config reloading #1771
feat: config reloading #1771
Conversation
This commit provides a basic primitive for the thread safe hot swapping of an active http.Handler. It works by wrapping an atomic.Value within a struct implementing the http.Handler interface. Before serving each request it first makes a load call on the atomic.Value, returning the most recently stored http.Handler. The package is accompanied by two tests, one to test the basic store & load support. The second test is meant to be ran only when the race detector is present.
I've added LoadDirectory and LoadFile with comments explaining the behavior of each. LoadGlobalFromEnv simply calls loadGlobal which configures a *GlobalConfiguration from the processes current env. These will be used to compose a *GlobalConfiguration from the multiple configuration sources during process initialization and during live reloads.
A new optional flag (long: --watch-dir, short: -w) has been added. When present any files with a ".env" suffix will be loaded into the environment before the *GlobalConfiguration is created, otherwise existing behavior is preserved. In addition when the watch-dir flag is present a goroutine will be started in serve_cmd.go and begin blocking on a call to (*Reloader).Watch with a callback function that accepts a *conf.GlobalConfiguration object. Each time this function is called we create a new API object and store it within our AtomicHandler, previously given as the root handler to the *http.Server. The Reloader uses some simple heuristics to deal with a few edge cases, an overview: - At most 1 configuration reload may happen per 10 seconds with a +-1s margin of error. - After a file within -watch-dir has changed the 10 second grace period begins. After that it will reload the config. - Config reloads first sort each file by name then processes them in sequence. - Directories within watch-dir are ignored during config reloading. - Implementation quirk: directory changes can trigger a config reload, as I don't stat fsnotify events. This and similar superfulous reloads could be easily fixed by storing a snapshot of os.Environ() after successful reloads to compare with the latest via slices.Equal() before reloading. - Files that do not end with a .env suffix are ignored. - It handles the removal or renaming of the -watch-dir during runtime, but an error message will be printed every 10 seconds as long as it's missing. - The config file passed with -c is only loaded once. Live reloads only read the config dir. Meaning it would be possible to create a config dir change that results in a new final configuration on the next reload due to the persistence of os.Environ().
@cstockton seems like some of the gosec tests are broken |
Pull Request Test Coverage Report for Build 10927565463Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice one @cstockton !
🤖 I have created a release *beep* *boop* --- ## [2.161.0](v2.160.0...v2.161.0) (2024-09-24) ### Features * add `x-sb-error-code` header, show error code in logs ([#1765](#1765)) ([ed91c59](ed91c59)) * add webauthn configuration variables ([#1773](#1773)) ([77d5897](77d5897)) * config reloading ([#1771](#1771)) ([6ee0091](6ee0091)) ### Bug Fixes * add additional information around errors for missing content type header ([#1576](#1576)) ([c2b2f96](c2b2f96)) * add token to hook payload for non-secure email change ([#1763](#1763)) ([7e472ad](7e472ad)) * update aal requirements to update user ([#1766](#1766)) ([25d9874](25d9874)) * update mfa admin methods ([#1774](#1774)) ([567ea7e](567ea7e)) * user sanitization should clean up email change info too ([#1759](#1759)) ([9d419b4](9d419b4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
What kind of change does this PR introduce?
File based configuration reloading using fsnotify.
What is the current behavior?
Currently the Auth config is loaded once from the environment or file (-c flag) and persists until the service is restarted.
What is the new behavior?
A new optional flag (long:
--watch-dir
, short:-w
) has been added. When present any files with a ".env" suffix will be loaded into the environment before the*GlobalConfiguration
is created, otherwise existing behavior is preserved.In addition when the watch-dir flag is present a goroutine will be started in serve_cmd.go and begin blocking on a call to
(*Reloader).Watch
with a callback function that accepts a*conf.GlobalConfiguration object
. Each time this function is called we create a new*api.API
object and store it within ourAtomicHandler
, previously given as the root handler to the*http.Server
.The Reloader uses some simple heuristics to deal with a few edge cases, an overview:
--watch-dir
has changed the 10 second grace period begins. After that it will reload the config.--watch-dir
are ignored during config reloading.os.Environ()
after successful reloads to compare with the latest viaslices.Equal()
before reloading..env
suffix are ignored.-watch-dir
during runtime, but an error message will be printed every 10 seconds as long as it's missing.os.Environ()
.