-
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 #1764
feat: config reloading #1764
Conversation
This latest commits contain the remainder of the initial draft of this feature. It's a little rough around the edges and I have some outstanding questions, but this will serve as a talking point. Feature Details:When watch-dir ( The Reloader uses some simple heuristics to deal with a few edge cases, an overview:
|
Moving to ready for review, few things to be made aware of: |
Maybe at least check if the change resulted in a file that would affect the change? Like a
Actually that's a good point. Maybe if the dir gets removed or moved to another location it should just panic? That's not something you want to do to a running server. I'd rather it fail early than continue with some invalid state. |
For directory changes I meant: changes within the directory that are a directory and not a file. For example: mkdir auth.d
cp -a example.env /auth.d/example.env
auth -w auth.d &
mkdir auth.d/i-am-a-directory-but-still-trigger-fsnotify I currently don't perform an os.Stat on each file change, thus I can't differentiate between dirs and files. If it becomes a common infra pattern to create another directory within the config dir it will result in superfluous reloads. I figured in practice this won't occur so avoiding the os.Stat is okay.
I do my best to make sure the auth server is only reloaded when the config file is valid, so the process will continue running in the last known good state. The main thing I was trying to mitigate with allowing it to recover from a temporarily missing config dir was someone doing: mkdir /auth.d.deploy
cp -a new-configs/* /auth.d.deploy
mv /auth.d /auth.d.rollback
mv /auth.d.deploy /auth.d I can panic if you would prefer once it's removed, just a little worried some infra tooling might end up doing an mv with staged config dir instead of modifying the existing one. If we decide not to panic, would you like me to implement log suppression? If so I can do something local to reloader if you don't have an existing pattern for that. |
cmd/root_cmd.go
Outdated
@@ -23,7 +26,7 @@ var rootCmd = cobra.Command{ | |||
func RootCommand() *cobra.Command { | |||
rootCmd.AddCommand(&serveCmd, &migrateCmd, &versionCmd, adminCmd()) | |||
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "the config file to use") | |||
|
|||
rootCmd.PersistentFlags().StringVarP(&watchDir, "watch-dir", "w", "", "config directory to watch for changes") |
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.
Maybe to be more explicit:
rootCmd.PersistentFlags().StringVarP(&watchDir, "watch-dir", "w", "", "config directory to watch for changes") | |
rootCmd.PersistentFlags().StringVarP(&watchDir, "watch-config-dir", "w", "", "config directory to watch for changes") |
internal/conf/configuration.go
Outdated
|
||
func LoadGlobalFiles(filenames ...string) (*GlobalConfiguration, error) { |
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.
Just double making sure, this will load config like:
- Environment
- File A
- File B
- File C
Right? Environment goes first?
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.
Correct, but the Environment is only used for startup. It is overwritten since godotenv writes to Go's copy of the process environment with os.Setenv. I didn't touch any of the logic for starting the process. I was thinking the purpose of keeping the -c flag was for the initialization and the config dir was for runtime changes that overwrote it. But maybe it shouldn't work this way?
How it works now:
# process
export GOTRUE_base_env_var_01=...
export GOTRUE_base_env_var_01=...
auth -c '/base.conf' -w '/auth.d'
Before the first request:
- os.Environ() already contains process values
conf.LoadGlobal("/base.conf")
- /base.conf is read, overriding any env vars (by godotenv.Override)
- OR
conf.LoadGlobal("")
(-c not flag empty or missing)- .env is optionally loading, env vars have precedence (godotenv.Load)
The root handler is constructed and begins serving requests with this initialization configuration. Nothing is touched in the -watch-dir
directory. If later on someone adds files there, they will start taking precedence. Since godotenv writes to the environment, they are lost if overwritten.
If auth.d should be part of initialization above we should probably make the two flags mutually exclusive, or define the ordering behavior concretely. That probably makes more sense come to think of it.
On both initialization and config.Reload, do the same exact behavior:
- conf.LoadGlobalFiles(base, configDirFiles...)
- first if base is "" (do as we do now)
- check for ".env", don't override env vars
- load base, override all env vars
- second if configDirFiles is not empty, load each one in sequence
- first if base is "" (do as we do now)
15b0d63
to
a6c1824
Compare
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?
The server may be configured with environment variables similar to today, but one or more additional configuration files may be provided as well as a flag to watch those files with fsnotify. When the files are updated the server will reload the configuration files and create a new
*api.API
object to be used in future requests.