Skip to content

Commit

Permalink
Service cleanup in Azure AI Search (#15063)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored and hishamco committed Feb 1, 2024
1 parent 8cce6be commit b2ef9d7
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services,
services.AddTransient<IConfigureOptions<AzureAISearchDefaultOptions>, AzureAISearchDefaultOptionsConfigurations>();

services.AddAzureClientsCore();
services.AddSingleton<SearchIndexClientAccessor>();

services.AddScoped<IPermissionProvider, Permissions>();
services.AddScoped<IContentHandler, AzureAISearchIndexingContentHandler>();
services.AddScoped<AzureAISearchIndexManager>();
services.AddScoped<AzureAIIndexDocumentManager>();
services.AddScoped<AzureAISearchIndexingService>();
services.AddSingleton<AzureAISearchIndexSettingsService>();
services.AddSingleton<SearchClientFactory>();
services.AddSingleton<AzureAIClientFactory>();

services.AddRecipeExecutionStep<AzureAISearchIndexRebuildStep>();
services.AddRecipeExecutionStep<AzureAISearchIndexResetStep>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Concurrent;
using Azure.Identity;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Microsoft.Extensions.Options;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI.Services;

public class AzureAIClientFactory(IOptions<AzureAISearchDefaultOptions> defaultOptions)
{
private readonly ConcurrentDictionary<string, SearchClient> _clients = [];
private readonly AzureAISearchDefaultOptions _defaultOptions = defaultOptions.Value;

private SearchIndexClient _searchIndexClient;

public SearchClient CreateSearchClient(string indexFullName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(indexFullName, nameof(indexFullName));

if (!_clients.TryGetValue(indexFullName, out var client))
{
if (!_defaultOptions.IsConfigurationExists())
{
throw new Exception("Azure AI was not configured.");
}

if (!Uri.TryCreate(_defaultOptions.Endpoint, UriKind.Absolute, out var endpoint))
{
throw new Exception("The Endpoint provided to Azure AI Options contains invalid value.");
}

if (_defaultOptions.AuthenticationType == AzureAIAuthenticationType.ApiKey && _defaultOptions.Credential != null)
{
client = new SearchClient(endpoint, indexFullName, _defaultOptions.Credential);
}
else if (_defaultOptions.AuthenticationType == AzureAIAuthenticationType.ManagedIdentity)
{
client = new SearchClient(endpoint, indexFullName, GetManagedIdentityCredential());
}
else
{
client = new SearchClient(endpoint, indexFullName, new DefaultAzureCredential());
}

_clients.TryAdd(indexFullName, client);
}

return client;
}

public SearchIndexClient CreateSearchIndexClient()
{
if (_searchIndexClient == null)
{
if (!_defaultOptions.IsConfigurationExists())
{
throw new Exception("Azure AI was not configured.");
}

if (!Uri.TryCreate(_defaultOptions.Endpoint, UriKind.Absolute, out var endpoint))
{
throw new Exception("The Endpoint provided to Azure AI Options contains invalid value.");
}

if (_defaultOptions.AuthenticationType == AzureAIAuthenticationType.ApiKey && _defaultOptions.Credential != null)
{
_searchIndexClient = new SearchIndexClient(endpoint, _defaultOptions.Credential);
}
else if (_defaultOptions.AuthenticationType == AzureAIAuthenticationType.ManagedIdentity)
{
_searchIndexClient = new SearchIndexClient(endpoint, GetManagedIdentityCredential());
}
else
{
_searchIndexClient = new SearchIndexClient(endpoint, new DefaultAzureCredential());
}
}

return _searchIndexClient;
}

private ManagedIdentityCredential GetManagedIdentityCredential()
=> new(_defaultOptions.IdentityClientId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
namespace OrchardCore.Search.AzureAI.Services;

public class AzureAIIndexDocumentManager(
SearchClientFactory searchClientFactory,
AzureAIClientFactory clientFactory,
AzureAISearchIndexManager indexManager,
IIndexingTaskManager indexingTaskManager,
IContentManager contentManager,
IEnumerable<IAzureAISearchDocumentEvents> documentEvents,
IEnumerable<IContentItemIndexHandler> contentItemIndexHandlers,
ILogger<AzureAIIndexDocumentManager> logger)
{
private readonly SearchClientFactory _searchClientFactory = searchClientFactory;
private readonly AzureAIClientFactory _clientFactory = clientFactory;
private readonly AzureAISearchIndexManager _indexManager = indexManager;
private readonly IIndexingTaskManager _indexingTaskManager = indexingTaskManager;
private readonly IContentManager _contentManager = contentManager;
Expand All @@ -38,7 +38,9 @@ public async Task<IEnumerable<SearchDocument>> SearchAsync(string indexName, str
var client = GetSearchClient(indexName);

var searchResult = await client.SearchAsync<SearchDocument>(searchText, searchOptions);

var docs = new List<SearchDocument>();

await foreach (var doc in searchResult.Value.GetResultsAsync())
{
docs.Add(doc.Document);
Expand Down Expand Up @@ -326,7 +328,7 @@ private SearchClient GetSearchClient(string indexName)
{
var fullIndexName = _indexManager.GetFullIndexName(indexName);

var client = _searchClientFactory.Create(fullIndexName) ?? throw new Exception("Endpoint is missing from Azure AI Search Settings");
var client = _clientFactory.CreateSearchClient(fullIndexName);

return client;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
namespace OrchardCore.Search.AzureAI.Services;

public class AzureAISearchIndexManager(
SearchIndexClientAccessor clientAccessor,
AzureAIClientFactory clientFactory,
ILogger<AzureAISearchIndexManager> logger,
IOptions<AzureAISearchDefaultOptions> azureAIOptions,
IEnumerable<IAzureAISearchIndexEvents> indexEvents,
Expand All @@ -30,7 +30,7 @@ public class AzureAISearchIndexManager(

private const string _prefixCacheKey = "AzureAISearchIndexesPrefix";

private readonly SearchIndexClientAccessor _clientAccessor = clientAccessor;
private readonly AzureAIClientFactory _clientFactory = clientFactory;
private readonly ILogger _logger = logger;
private readonly IEnumerable<IAzureAISearchIndexEvents> _indexEvents = indexEvents;
private readonly IMemoryCache _memoryCache = memoryCache;
Expand All @@ -52,7 +52,9 @@ public async Task<bool> CreateAsync(AzureAISearchIndexSettings settings)

var searchIndex = GetSearchIndex(context.IndexFullName, settings);

var response = await _clientAccessor.Get().CreateIndexAsync(searchIndex);
var client = _clientFactory.CreateSearchIndexClient();

var response = client.CreateIndexAsync(searchIndex);

await _indexEvents.InvokeAsync((handler, ctx) => handler.CreatedAsync(ctx), context, _logger);

Expand All @@ -74,7 +76,10 @@ public async Task<SearchIndex> GetAsync(string indexName)
try
{
var indexFullName = GetFullIndexName(indexName);
var response = await _clientAccessor.Get().GetIndexAsync(indexFullName);

var client = _clientFactory.CreateSearchIndexClient();

var response = await client.GetIndexAsync(indexFullName);

return response?.Value;
}
Expand Down Expand Up @@ -106,7 +111,9 @@ public async Task<bool> DeleteAsync(string indexName)

await _indexEvents.InvokeAsync((handler, ctx) => handler.RemovingAsync(ctx), context, _logger);

var response = await _clientAccessor.Get().DeleteIndexAsync(context.IndexFullName);
var client = _clientFactory.CreateSearchIndexClient();

var response = await client.DeleteIndexAsync(context.IndexFullName);

await _indexEvents.InvokeAsync((handler, ctx) => handler.RemovedAsync(ctx), context, _logger);

Expand All @@ -128,14 +135,16 @@ public async Task RebuildAsync(AzureAISearchIndexSettings settings)

await _indexEvents.InvokeAsync((handler, ctx) => handler.RebuildingAsync(ctx), context, _logger);

var client = _clientFactory.CreateSearchIndexClient();

if (await ExistsAsync(settings.IndexName))
{
await _clientAccessor.Get().DeleteIndexAsync(context.IndexFullName);
await client.DeleteIndexAsync(context.IndexFullName);
}

var searchIndex = GetSearchIndex(context.IndexFullName, settings);

var response = await _clientAccessor.Get().CreateIndexAsync(searchIndex);
var response = await client.CreateIndexAsync(searchIndex);

await _indexEvents.InvokeAsync((handler, ctx) => handler.RebuiltAsync(ctx), context, _logger);
}
Expand Down

This file was deleted.

This file was deleted.

0 comments on commit b2ef9d7

Please sign in to comment.