Search code examples
c#azure-cognitive-searchazure-search-.net-sdk

Periodically reload credentials on SearchServiceClient and child ISearchIndexClient singletons


In our web app dependency injection, we configure the ISearchIndexClient instances returned by .NET Azure Search SDK's SearchServiceClient.Indexes.GetClient(...) as a singletons.

We did this because of the answer https://stackoverflow.com/a/43502662 mentions that these classes share a single HTTP client. To avoid port exhaustion we want a single shared HttpClient.

The problem with this, however, is that this means we need to restart the web app to cause the new query key (secret) to be reloaded from KeyVault. Consider a secret rotation flow: we need to restart/redeploy our web app after putting the new secret in KeyVault but before invalidating the old secret.

Is there a factory or another pattern the Azure Search .NET SDK recommends for periodically getting a new SearchServiceClient or ISearchIndexClient? I want a singleton most of the time for performance reasons but would like a new instance every couple of hours (for example).

Our code looks something like this right now. It uses Autofac but I think it gets the point across:

containerBuilder
    .Register(c =>
    {
        var options = c.Resolve<IOptionsSnapshot<AzureSearchConfiguration>>();
        return new SearchServiceClient(
            options.Value.SearchServiceName,
            new SearchCredentials(options.Value.SearchServiceApiKey));
    });

containerBuilder
    .Register(c =>
    {
        var serviceClient = c.Resolve<SearchServiceClient>();
        var options = c.Resolve<IOptionsSnapshot<AzureSearchConfiguration>>();
        return serviceClient.Indexes.GetClient(options.Value.SearchIndexName);
    })
    .SingleInstance();

I can build a time-based factory that spits out a new SearchServiceClient or ISearchIndexClient from time to time but I was hoping that something already existed.


Solution

  • Implementing your own factory/pool for SearchIndexClient instances is the way to go. Unfortunately this kind of functionality isn't included in the SDK, so you'll have to roll your own.