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

Hot Reload Validation #2405

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

RubenCerna2079
Copy link
Contributor

@RubenCerna2079 RubenCerna2079 commented Oct 2, 2024

Why make this change?

This change fixes issue #2396

What is this change?

In order to validate the hot-reload, first, new logic was added to the RuntimeConfigLoader and FileSystemRuntimeConfigLoader, so when hot reload occurs, it updates the new states added to the loader which are isNewConfigDetected, isNewConfigValidated, and lastValidRuntimeConfig.
Once the states are updated, it will try to parse and validate the new RuntimeConfig, in the case that it fails at any step of the way, the hot-reloading process will be canceled and the RuntimeConfig file will be changed so that it uses the information from lastValidRuntimeConfig so that the user can still use their last configuration without any problems.

How was this tested?

  • Integration Tests
  • Unit Tests

Comment on lines +82 to +85
IFileSystem fileSystem = new FileSystem();
ILoggerFactory loggerFactory = new LoggerFactory();
ILogger<RuntimeConfigValidator> logger = loggerFactory.CreateLogger<RuntimeConfigValidator>();
RuntimeConfigValidator runtimeConfigValidator = new(this, fileSystem, logger, true);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if this is fine, since there is no logger inside the provider

Copy link
Contributor

Choose a reason for hiding this comment

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

For now, this is the only straightforward way of achieving validation during a hot reload.

My original response was the following, however we need to re-evaluate how we configure services in startup.cs such that we don't need to have runtimeconfigprovider resolved. That will need to be tracked via a separate task.
--------------------Obsolete-----------------------
There looks to be a better way of accomplishing instantiation of the RuntimeConfigValidator.

In Startup.cs:

            IFileSystem fileSystem = new FileSystem();
            FileSystemRuntimeConfigLoader configLoader = new(fileSystem, hotReloadEventHandler, configFileName, connectionString);
            RuntimeConfigProvider configProvider = new(configLoader);
            RuntimeConfigValidator configValidator = new(
                runtimeConfigProvider: configProvider, 
                fileSystem: fileSystem, 
                logger: , // this is an issue, we can't resolve an ilogger in Startup::ConfigureServices
                isValidateOnly: true);
            services.AddSingleton(fileSystem);
            services.AddSingleton(configProvider);
            services.AddSingleton(configLoader);
            services.AddSingleton<configValidator>(); // instead of "services.AddSingleton<RuntimeConfigValidator>();"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was not able to find the code you put from Startup.cs and that way of instantiating RuntimeConfigValidator did not work for me.

@RubenCerna2079
Copy link
Contributor Author

/azp run

Copy link

Pull request contains merge conflicts.

@RubenCerna2079 RubenCerna2079 linked an issue Oct 3, 2024 that may be closed by this pull request
@RubenCerna2079 RubenCerna2079 self-assigned this Oct 7, 2024
src/Config/FileSystemRuntimeConfigLoader.cs Outdated Show resolved Hide resolved
src/Config/RuntimeConfigLoader.cs Outdated Show resolved Hide resolved
src/Core/Configurations/RuntimeConfigProvider.cs Outdated Show resolved Hide resolved
src/Core/Configurations/RuntimeConfigProvider.cs Outdated Show resolved Hide resolved
src/Core/Services/OpenAPI/OpenApiDocumentor.cs Outdated Show resolved Hide resolved
src/Core/Configurations/RuntimeConfigProvider.cs Outdated Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

You should add a little more detail to your PR description describing how these mechanisms work:

  1. Hot Reload occurs which updates state in the Loader -> NewConfigDetected, isNewConfigValidated, "used"/newRuntimeConfigObject
  2. any service which attempts to RuntimeConfigProvider::GetRuntimeConfig() will trigger RuntimeConfigProvider::GetRuntimeConfig()'s internal logic to check the loaders state for isnewconfigValidated, and attempt to validate the config. then return the validated config.
    Then describe what the expectations should be when a hotreloadedconfig is invalid.
    Another thing to think about:
  3. do we need to introduce a lock in RuntimeConfigProvider::GetRuntimeConfig() if the condition holds that the new runtimeconfig needs validation? e.g. if multiple dependent services attempt to fetch a hotreloaded config, only only operation should trigger validation, and the remaining callers can utilize that result as opposed to trigger multiple validation operations on the same config.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. Updated the description
  2. I changed it so that FileSystemRuntimeConfig::HotReloadConfig() is the one that changes the state of isNewConfigValidated and isNewConfigDetected, so I believe that the internal logic to validate the config will only happen when there is a hot reload.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. The changes I made, make it so that it only makes the validation on the first OnConfigChangeEvent while the others use the result.

@RubenCerna2079
Copy link
Contributor Author

/azp run

@RubenCerna2079
Copy link
Contributor Author

/azp run

1 similar comment
@RubenCerna2079
Copy link
Contributor Author

/azp run

Comment on lines +97 to +103
_configLoader.isNewConfigValidated = true;
_configLoader.RuntimeConfig = _configLoader.lastValidRuntimeConfig;

throw new DataApiBuilderException(
message: "Failed validation of configuration file.",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorInInitialization);
Copy link
Contributor

Choose a reason for hiding this comment

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

Because you're reverting to a Last Known Good (LKG) runtimeconfig where isNewConfigValidated is true:

  1. Do you still need to raise an exception?
  2. What would catch that exception and would such an exception imply that DAB should shut down?

Copy link
Contributor Author

@RubenCerna2079 RubenCerna2079 Oct 15, 2024

Choose a reason for hiding this comment

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

I still think that we should raise an exception that allows the user to know that their changes to the hot reload were not successful and that they are using their old configuration settings. As for the exception, it is catched in ConfigFileWatcher::OnConfigFileChange which from my understanding, implies that DAB should still be running, and it gives a chance to the user to correctly change their config file for hot reload.


public bool isNewConfigDetected;

public bool isNewConfigValidated = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this default to false? only switch to true when validated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, isNewConfigDetected is by default false and should only switch to true when there is going to be a hot-reload

Comment on lines +97 to +98
_configLoader.isNewConfigValidated = true;
_configLoader.RuntimeConfig = _configLoader.lastValidRuntimeConfig;
Copy link
Contributor

Choose a reason for hiding this comment

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

perhaps this should be a function internal to the ConfigLoader so that ConfigLoader handles its own state whenever possible versus the Provider doing it, What do you think of this?

_configLoader.RestoreLkgConfig() -> internally restores loader.lastValidConfig to loader.Config

Comment on lines +82 to +85
IFileSystem fileSystem = new FileSystem();
ILoggerFactory loggerFactory = new LoggerFactory();
ILogger<RuntimeConfigValidator> logger = loggerFactory.CreateLogger<RuntimeConfigValidator>();
RuntimeConfigValidator runtimeConfigValidator = new(this, fileSystem, logger, true);
Copy link
Contributor

Choose a reason for hiding this comment

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

For now, this is the only straightforward way of achieving validation during a hot reload.

My original response was the following, however we need to re-evaluate how we configure services in startup.cs such that we don't need to have runtimeconfigprovider resolved. That will need to be tracked via a separate task.
--------------------Obsolete-----------------------
There looks to be a better way of accomplishing instantiation of the RuntimeConfigValidator.

In Startup.cs:

            IFileSystem fileSystem = new FileSystem();
            FileSystemRuntimeConfigLoader configLoader = new(fileSystem, hotReloadEventHandler, configFileName, connectionString);
            RuntimeConfigProvider configProvider = new(configLoader);
            RuntimeConfigValidator configValidator = new(
                runtimeConfigProvider: configProvider, 
                fileSystem: fileSystem, 
                logger: , // this is an issue, we can't resolve an ilogger in Startup::ConfigureServices
                isValidateOnly: true);
            services.AddSingleton(fileSystem);
            services.AddSingleton(configProvider);
            services.AddSingleton(configLoader);
            services.AddSingleton<configValidator>(); // instead of "services.AddSingleton<RuntimeConfigValidator>();"

@@ -74,6 +76,34 @@ public RuntimeConfigProvider(RuntimeConfigLoader runtimeConfigLoader)
/// <exception cref="DataApiBuilderException">Thrown when the loader is unable to load an instance of the config from its known location.</exception>
public RuntimeConfig GetConfig()
{
// Only used in hot reload to validate the configuration file
if (_configLoader.isNewConfigDetected && !_configLoader.isNewConfigValidated)
Copy link
Contributor

Choose a reason for hiding this comment

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

your pr description checks the box for "integration tests." how do existing integration tests check hot reload and this new functionality? I'd suggest outline in your PR description how you tested this, even if manually tested.

message: "Failed validation of configuration file.",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorInInitialization);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

how have we tested this? Is there a way to add an automated integration test in ConfigurationTests.cs?

@@ -31,6 +31,12 @@ public abstract class RuntimeConfigLoader
// state in place of using out params.
public RuntimeConfig? RuntimeConfig;

public RuntimeConfig? lastValidRuntimeConfig;
Copy link
Contributor

Choose a reason for hiding this comment

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

All these properties are public properties. So, naming convention wise they should be capitalized. LastValidRuntimeConfig, IsNewConfigDetected, IsNewConfigValidated.

Copy link
Contributor

@Aniruddh25 Aniruddh25 left a comment

Choose a reason for hiding this comment

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

Waiting for testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hot-Reload Validate New Config File
4 participants