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 MetadataProvider initialization in Hot Reload and remove duplicate Query Executor reloading #2428

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/Config/FileSystemRuntimeConfigLoader.cs
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add more detail in pr description for how you manually tested these changes. Use
#2417 and #2414 as examples via the "test scenarios" sections

Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,6 @@ public bool TryLoadConfig(
logger?.LogInformation("Monitoring config: {ConfigFilePath} for hot-reloading.", ConfigFilePath);
}

if (!string.IsNullOrEmpty(defaultDataSourceName))
{
RuntimeConfig.DefaultDataSourceName = defaultDataSourceName;
}

config = RuntimeConfig;
return true;
}
Expand Down
4 changes: 0 additions & 4 deletions src/Config/HotReloadEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ public HotReloadEventHandler()
{ METADATA_PROVIDER_FACTORY_ON_CONFIG_CHANGED, null },
{ QUERY_ENGINE_FACTORY_ON_CONFIG_CHANGED,null },
{ MUTATION_ENGINE_FACTORY_ON_CONFIG_CHANGED,null },
{ QUERY_EXECUTOR_ON_CONFIG_CHANGED, null },
{ MSSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, null },
{ MYSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, null },
{ POSTGRESQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, null },
Comment on lines -29 to -32
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add comment surrounding QUERY_MANAGER_FACTORY_ON_CONFIG_CHANGED here that describes how the "query executors since those are already being correctly refreshed already by the query manager factory reload process."

{ DOCUMENTOR_ON_CONFIG_CHANGED, null }
};
}
Expand Down
11 changes: 8 additions & 3 deletions src/Config/ObjectModel/RuntimeConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,12 @@ public bool TryGetEntityNameFromPath(string entityPathName, [NotNullWhen(true)]
/// <param name="Runtime">Runtime settings.</param>
/// <param name="DataSourceFiles">List of datasource files for multiple db scenario. Null for single db scenario.</param>
[JsonConstructor]
public RuntimeConfig(string? Schema, DataSource DataSource, RuntimeEntities Entities, RuntimeOptions? Runtime = null, DataSourceFiles? DataSourceFiles = null)
public RuntimeConfig(
string? Schema,
DataSource DataSource,
RuntimeEntities Entities,
RuntimeOptions? Runtime = null,
DataSourceFiles? DataSourceFiles = null)
{
this.Schema = Schema ?? DEFAULT_CONFIG_SCHEMA_LINK;
this.DataSource = DataSource;
Expand All @@ -189,13 +194,13 @@ public RuntimeConfig(string? Schema, DataSource DataSource, RuntimeEntities Enti
// we will set them up with default values
_dataSourceNameToDataSource = new Dictionary<string, DataSource>
{
{ DefaultDataSourceName, this.DataSource }
{ this.DefaultDataSourceName, this.DataSource }
};

_entityNameToDataSourceName = new Dictionary<string, string>();
foreach (KeyValuePair<string, Entity> entity in Entities)
{
_entityNameToDataSourceName.TryAdd(entity.Key, DefaultDataSourceName);
_entityNameToDataSourceName.TryAdd(entity.Key, this.DefaultDataSourceName);
}

// Process data source and entities information for each database in multiple database scenario.
Expand Down
17 changes: 3 additions & 14 deletions src/Config/RuntimeConfigLoader.cs
Copy link
Contributor

Choose a reason for hiding this comment

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

can you add more details to the PR description for why we need to change how dataSourceName is used: using the passed in argument versus using the "default" data source name.

Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ protected void SendEventNotification(string message = "")
OnConfigChangedEvent(new HotReloadEventArgs(METADATA_PROVIDER_FACTORY_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(QUERY_ENGINE_FACTORY_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(MUTATION_ENGINE_FACTORY_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(QUERY_EXECUTOR_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(MSSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(MYSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(POSTGRESQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, message));
OnConfigChangedEvent(new HotReloadEventArgs(DOCUMENTOR_ON_CONFIG_CHANGED, message));
}

Expand Down Expand Up @@ -97,7 +93,6 @@ public static bool TryParseConfig(string json,
ILogger? logger = null,
string? connectionString = null,
bool replaceEnvVar = false,
string dataSourceName = "",
Copy link

Choose a reason for hiding this comment

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

string dataSourceName = "",
If this has been removed, we should modify the doc string

Dictionary<string, string>? datasourceNameToConnectionString = null,
EnvironmentVariableReplacementFailureMode replacementFailureMode = EnvironmentVariableReplacementFailureMode.Throw)
{
Expand All @@ -113,13 +108,7 @@ public static bool TryParseConfig(string json,
}

// retreive current connection string from config
string updatedConnectionString = config.DataSource.ConnectionString;

// set dataSourceName to default if not provided
if (string.IsNullOrEmpty(dataSourceName))
{
dataSourceName = config.DefaultDataSourceName;
}
string updatedConnectionString = config.DataSource.ConnectionString;

if (!string.IsNullOrEmpty(connectionString))
{
Expand All @@ -133,7 +122,7 @@ public static bool TryParseConfig(string json,
}
Copy link

Choose a reason for hiding this comment

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

We should put Dictionary<string, string>? datasourceNameToConnectionString = new Dictionary<string, string>(); in the function defination itself instead of putting null there and then checking and replacing it with new object here.


// add to dictionary if datasourceName is present (will either be the default or the one provided)
datasourceNameToConnectionString.TryAdd(dataSourceName, updatedConnectionString);
datasourceNameToConnectionString.TryAdd(config.DefaultDataSourceName, updatedConnectionString);

// iterate over dictionary and update runtime config with connection strings.
foreach ((string dataSourceKey, string connectionValue) in datasourceNameToConnectionString)
Expand All @@ -153,7 +142,7 @@ public static bool TryParseConfig(string json,
}

ds = ds with { ConnectionString = updatedConnection };
config.UpdateDataSourceNameToDataSource(dataSourceName, ds);
config.UpdateDataSourceNameToDataSource(config.DefaultDataSourceName, ds);

if (string.Equals(dataSourceKey, config.DefaultDataSourceName, StringComparison.OrdinalIgnoreCase))
{
Expand Down
15 changes: 0 additions & 15 deletions src/Core/Resolvers/MsSqlQueryExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Logging;
using static Azure.DataApiBuilder.Config.DabConfigEvents;

namespace Azure.DataApiBuilder.Core.Resolvers
{
Expand Down Expand Up @@ -77,7 +76,6 @@ public MsSqlQueryExecutor(
httpContextAccessor,
handler)
{
handler?.Subscribe(MSSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, OnConfigChanged);
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_dataSourceToSessionContextUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = runtimeConfigProvider.ManagedIdentityAccessToken;
Expand Down Expand Up @@ -109,19 +107,6 @@ private void ConfigureMsSqlQueryEecutor()
}
}

/// <summary>
/// Function registered for callback during a hot-reload scenario.
/// </summary>
/// <param name="sender">The calling object.</param>
/// <param name="args">Event arguments.</param>
public void MsSqlQueryExecutorOnConfigChanged(object? sender, HotReloadEventArgs args)
{
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_dataSourceToSessionContextUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = _runtimeConfigProvider.ManagedIdentityAccessToken;
ConfigureMsSqlQueryEecutor();
}

/// <summary>
/// Modifies the properties of the supplied connection to support managed identity access.
/// In the case of MsSql, gets access token if deemed necessary and sets it on the connection.
Expand Down
14 changes: 0 additions & 14 deletions src/Core/Resolvers/MySqlQueryExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MySqlConnector;
using static Azure.DataApiBuilder.Config.DabConfigEvents;

namespace Azure.DataApiBuilder.Core.Resolvers
{
Expand Down Expand Up @@ -67,7 +66,6 @@ public MySqlQueryExecutor(
httpContextAccessor,
handler)
{
handler?.Subscribe(MYSQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, MySqlQueryExecutorOnConfigChanged);
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = runtimeConfigProvider.ManagedIdentityAccessToken;
_runtimeConfigProvider = runtimeConfigProvider;
Expand Down Expand Up @@ -100,18 +98,6 @@ private void ConfigureMySqlQueryExecutor()
}
}

/// <summary>
/// Function registered for callback during a hot-reload scenario.
/// </summary>
/// <param name="sender">The calling object.</param>
/// <param name="args">Event arguments.</param>
public void MySqlQueryExecutorOnConfigChanged(object? sender, HotReloadEventArgs args)
{
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = _runtimeConfigProvider.ManagedIdentityAccessToken;
ConfigureMySqlQueryExecutor();
}

/// <summary>
/// Modifies the properties of the supplied connection to support managed identity access.
/// In the case of MySql, gets access token if deemed necessary and sets it on the connection.
Expand Down
14 changes: 0 additions & 14 deletions src/Core/Resolvers/PostgreSqlExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Npgsql;
using static Azure.DataApiBuilder.Config.DabConfigEvents;

namespace Azure.DataApiBuilder.Core.Resolvers
{
Expand Down Expand Up @@ -68,7 +67,6 @@ public PostgreSqlQueryExecutor(
httpContextAccessor,
handler)
{
handler?.Subscribe(POSTGRESQL_QUERY_EXECUTOR_ON_CONFIG_CHANGED, PostgreSqlQueryExecutorOnConfigChanged);
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = runtimeConfigProvider.ManagedIdentityAccessToken;
_runtimeConfigProvider = runtimeConfigProvider;
Expand Down Expand Up @@ -97,18 +95,6 @@ private void ConfigurePostgreSqlQueryExecutor()
}
}

/// <summary>
/// Function registered for callback during a hot-reload scenario.
/// </summary>
/// <param name="sender">The calling object.</param>
/// <param name="args">Event arguments.</param>
public void PostgreSqlQueryExecutorOnConfigChanged(object? sender, HotReloadEventArgs args)
{
_dataSourceAccessTokenUsage = new Dictionary<string, bool>();
_accessTokensFromConfiguration = _runtimeConfigProvider.ManagedIdentityAccessToken;
ConfigurePostgreSqlQueryExecutor();
}

/// <summary>
/// Modifies the properties of the supplied connection string to support managed identity access.
/// In the case of Postgres, if a default managed identity needs to be used, the password in the
Expand Down
14 changes: 0 additions & 14 deletions src/Core/Resolvers/QueryExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
using Microsoft.Extensions.Logging;
using Polly;
using Polly.Retry;
using static Azure.DataApiBuilder.Config.DabConfigEvents;

namespace Azure.DataApiBuilder.Core.Resolvers
{
Expand Down Expand Up @@ -56,7 +55,6 @@ public QueryExecutor(DbExceptionParser dbExceptionParser,
IHttpContextAccessor httpContextAccessor,
HotReloadEventHandler<HotReloadEventArgs>? handler)
{
handler?.Subscribe(QUERY_EXECUTOR_ON_CONFIG_CHANGED, OnConfigChanged);
DbExceptionParser = dbExceptionParser;
QueryExecutorLogger = logger;
ConnectionStringBuilders = new Dictionary<string, DbConnectionStringBuilder>();
Expand Down Expand Up @@ -86,18 +84,6 @@ public QueryExecutor(DbExceptionParser dbExceptionParser,
});
}

/// <summary>
/// Function registered for callback during a hot-reload scenario.
/// </summary>
/// <param name="sender">The calling object.</param>
/// <param name="args">Event arguments.</param>
public void OnConfigChanged(object? sender, HotReloadEventArgs args)
{
ConnectionStringBuilders = new Dictionary<string, DbConnectionStringBuilder>();
_maxResponseSizeMB = ConfigProvider.GetConfig().MaxResponseSizeMB();
_maxResponseSizeBytes = _maxResponseSizeMB * 1024 * 1024;
}

/// <inheritdoc/>
public virtual TResult? ExecuteQuery<TResult>(
string sqltext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Azure.DataApiBuilder.Core.Services.MetadataProviders
/// <inheritdoc />
public class MetadataProviderFactory : IMetadataProviderFactory
{
private readonly IDictionary<string, ISqlMetadataProvider> _metadataProviders;
private IDictionary<string, ISqlMetadataProvider> _metadataProviders;
Copy link
Contributor

Choose a reason for hiding this comment

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

just for new allocation, we shouldn't change its access modifier

private readonly RuntimeConfigProvider _runtimeConfigProvider;
private readonly IAbstractQueryManagerFactory _queryManagerFactory;
private readonly ILogger<ISqlMetadataProvider> _logger;
Expand Down Expand Up @@ -62,7 +62,10 @@ private void ConfigureMetadataProviders()

public void OnConfigChanged(object? sender, HotReloadEventArgs args)
{
_metadataProviders = new Dictionary<string, ISqlMetadataProvider>();
Copy link
Contributor

Choose a reason for hiding this comment

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

better to clear() because it avoids re-allocating the _metadataProviders dictionary every time the OnConfigChanged method is called. it is more efficient in terms of memory and performance.

I'll address it in my PR. so you can remove revert this

ConfigureMetadataProviders();
// Blocks the current thread until initialization is finished.
this.InitializeAsync().GetAwaiter().GetResult();
aaronburtle marked this conversation as resolved.
Show resolved Hide resolved
}

/// <inheritdoc />
Expand Down