-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Incremental work * Incremental work * Incremental work * Merge remote-tracking branch 'origin/v3' into v3-elasticsearch-updates * Incremental work * Incremental work * Fix listing with no query * Restore missing class * Remove rollover hosted service and expose index configurations * Rename hosted service
- Loading branch information
1 parent
dad33e6
commit 096206d
Showing
66 changed files
with
869 additions
and
454 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 0 additions & 9 deletions
9
src/modules/Elsa.Elasticsearch/Common/ElasticConfiguration.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,94 @@ | ||
using System.Collections.ObjectModel; | ||
using Elastic.Clients.Elasticsearch; | ||
using Elsa.Common.Models; | ||
using JetBrains.Annotations; | ||
using Microsoft.Extensions.Logging; | ||
using Exception = System.Exception; | ||
|
||
namespace Elsa.Elasticsearch.Common; | ||
|
||
/// <summary> | ||
/// A thin wrapper around <see cref="ElasticsearchClient"/> for easy re-usability. | ||
/// </summary> | ||
/// <typeparam name="T">The document type.</typeparam> | ||
[PublicAPI] | ||
public class ElasticStore<T> where T : class | ||
{ | ||
private readonly ElasticsearchClient _elasticClient; | ||
private readonly ILogger _logger; | ||
|
||
/// <summary> | ||
/// Constructor. | ||
/// </summary> | ||
public ElasticStore(ElasticsearchClient elasticClient, ILogger<ElasticStore<T>> logger) | ||
{ | ||
_elasticClient = elasticClient; | ||
_logger = logger; | ||
} | ||
|
||
/// <summary> | ||
/// Searches the index using the specified search descriptor. | ||
/// </summary> | ||
public async Task<Page<T>> SearchAsync(Action<SearchRequestDescriptor<T>> search, PageArgs? pageArgs, CancellationToken cancellationToken) | ||
{ | ||
if (pageArgs != default) | ||
if (pageArgs?.Page != null && pageArgs?.PageSize != null) | ||
{ | ||
search += s => s.From(pageArgs.Offset).Size(pageArgs.Limit); | ||
} | ||
|
||
var response = await _elasticClient.SearchAsync(search, cancellationToken); | ||
|
||
if (response.IsSuccess()) | ||
return new Page<T>(response.Hits.Select(hit => hit.Source).ToList()!, response.Total); | ||
|
||
_logger.LogError("Failed to search data in Elasticsearch: {message}", response.ElasticsearchServerError.ToString()); | ||
return new Page<T>(new Collection<T>(), 0); | ||
|
||
if (!response.IsSuccess()) | ||
throw new Exception(response.DebugInformation); | ||
|
||
return new Page<T>(response.Hits.Select(hit => hit.Source).ToList()!, response.Total); | ||
} | ||
|
||
public async Task SaveAsync(T model, CancellationToken cancellationToken) | ||
/// <summary> | ||
/// Stores the specified document in the index. | ||
/// </summary> | ||
public async Task SaveAsync(T document, CancellationToken cancellationToken) | ||
{ | ||
var response = await _elasticClient.IndexAsync(model, cancellationToken); | ||
var response = await _elasticClient.IndexAsync(document, cancellationToken); | ||
|
||
if (response.IsSuccess()) return; | ||
|
||
throw new Exception($"Failed to save data in Elasticsearch: {response.ElasticsearchServerError}"); | ||
if (!response.IsSuccess()) | ||
throw new Exception($"Failed to save data in Elasticsearch: {response.ElasticsearchServerError}"); | ||
} | ||
|
||
/// <summary> | ||
/// Stores the specified documents in the index. | ||
/// </summary> | ||
public async Task SaveManyAsync(IEnumerable<T> documents, CancellationToken cancellationToken) | ||
{ | ||
var response = await _elasticClient.IndexManyAsync(documents, cancellationToken); | ||
|
||
if (response.IsSuccess()) return; | ||
|
||
throw new Exception($"Failed to save data in Elasticsearch: {response.ElasticsearchServerError}"); | ||
if (!response.IsSuccess()) | ||
throw new Exception($"Failed to save data in Elasticsearch: {response.ElasticsearchServerError}"); | ||
} | ||
|
||
public async Task<long> DeleteManyAsync(IEnumerable<T> list, CancellationToken cancellationToken) | ||
/// <summary> | ||
/// Deletes the specified set of documents from the index. | ||
/// </summary> | ||
public async Task<long> DeleteManyAsync(IEnumerable<T> documents, CancellationToken cancellationToken) | ||
{ | ||
var response = await _elasticClient.BulkAsync(b => b.DeleteMany(list), cancellationToken); | ||
if (response.IsSuccess()) return response.Items.Count(i => i.IsValid); | ||
|
||
_logger.LogError("Failed to bulk delete data in Elasticsearch: {message}", response.ElasticsearchServerError.ToString()); | ||
return 0; | ||
var response = await _elasticClient.BulkAsync(b => b.DeleteMany(documents), cancellationToken); | ||
|
||
if (!response.IsSuccess()) | ||
throw new Exception(response.DebugInformation); | ||
|
||
return response.Items.Count(i => i.IsValid); | ||
} | ||
|
||
/// <summary> | ||
/// Deletes the documents matching the specified query. | ||
/// </summary> | ||
public async Task<long> DeleteByQueryAsync(Action<DeleteByQueryRequestDescriptor<T>> query, CancellationToken cancellationToken) | ||
{ | ||
var response = await _elasticClient.DeleteByQueryAsync(Indices.All, query, cancellationToken); | ||
|
||
if (response.IsSuccess()) return response.Deleted ?? 0; | ||
|
||
_logger.LogError("Failed to delete data in Elasticsearch: {message}", response.ElasticsearchServerError.ToString()); | ||
return 0; | ||
if (!response.IsSuccess()) | ||
throw new Exception(response.DebugInformation); | ||
|
||
return response.Deleted ?? 0; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/modules/Elsa.Elasticsearch/Common/IndexConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using Elastic.Clients.Elasticsearch; | ||
using Elsa.Elasticsearch.Services; | ||
using Elsa.Elasticsearch.Strategies; | ||
|
||
namespace Elsa.Elasticsearch.Common; | ||
|
||
/// <summary> | ||
/// A convenience base class for document type configurations. | ||
/// </summary> | ||
public abstract class IndexConfiguration<T> : IIndexConfiguration<T> | ||
{ | ||
/// <inheritdoc /> | ||
public Type DocumentType => typeof(T); | ||
|
||
/// <inheritdoc /> | ||
public virtual IIndexNamingStrategy IndexNamingStrategy => new DefaultNaming(); | ||
|
||
/// <inheritdoc /> | ||
public abstract void ConfigureClientSettings(ElasticsearchClientSettings settings); | ||
|
||
/// <inheritdoc /> | ||
public virtual ValueTask ConfigureClientAsync(ElasticsearchClient client, CancellationToken cancellationToken) => ValueTask.CompletedTask; | ||
} |
17 changes: 16 additions & 1 deletion
17
src/modules/Elsa.Elasticsearch/Common/PersistenceFeatureBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,34 @@ | ||
using Elsa.Elasticsearch.Services; | ||
using Elsa.Features.Abstractions; | ||
using Elsa.Features.Services; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Elsa.Elasticsearch.Common; | ||
|
||
/// <summary> | ||
/// Base class for features that configure Elasticsearch persistence. | ||
/// </summary> | ||
public abstract class ElasticPersistenceFeatureBase : FeatureBase | ||
{ | ||
public ElasticPersistenceFeatureBase(IModule module) : base(module) | ||
/// <inheritdoc /> | ||
protected ElasticPersistenceFeatureBase(IModule module) : base(module) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Registers an <see cref="ElasticStore{T}"/>. | ||
/// </summary> | ||
/// <typeparam name="TModel">The entity type of the store.</typeparam> | ||
/// <typeparam name="TStore">The type of the store.</typeparam> | ||
protected void AddStore<TModel, TStore>() where TModel : class where TStore : class | ||
{ | ||
Services | ||
.AddSingleton<ElasticStore<TModel>>() | ||
.AddSingleton<TStore>(); | ||
} | ||
|
||
/// <summary> | ||
/// Registers an <see cref="IIndexConfiguration"/>. | ||
/// </summary> | ||
protected void AddIndexConfiguration<TDocument>(Func<IServiceProvider, IIndexConfiguration<TDocument>> configuration) => Services.AddSingleton<IIndexConfiguration>(configuration); | ||
} |
This file was deleted.
Oops, something went wrong.
43 changes: 1 addition & 42 deletions
43
src/modules/Elsa.Elasticsearch/Extensions/ElasticExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,18 @@ | ||
using Elastic.Clients.Elasticsearch; | ||
using Elastic.Clients.Elasticsearch.IndexManagement; | ||
using Elastic.Transport; | ||
using Elsa.Elasticsearch.Common; | ||
using Elsa.Elasticsearch.Models; | ||
using Elsa.Elasticsearch.Options; | ||
using Elsa.Elasticsearch.Services; | ||
|
||
namespace Elsa.Elasticsearch.Extensions; | ||
|
||
public static class ElasticExtensions | ||
internal static class ElasticExtensions | ||
{ | ||
public static ElasticsearchClientSettings ConfigureAuthentication(this ElasticsearchClientSettings settings, ElasticsearchOptions options) | ||
{ | ||
if (!string.IsNullOrEmpty(options.ApiKey)) | ||
{ | ||
settings.Authentication(new ApiKey(options.ApiKey)); | ||
} | ||
else if (!string.IsNullOrEmpty(options.Username) && !string.IsNullOrEmpty(options.Password)) | ||
{ | ||
settings.Authentication(new BasicAuthentication(options.Username, options.Password)); | ||
} | ||
|
||
return settings; | ||
} | ||
|
||
public static ElasticsearchClientSettings ConfigureMapping(this ElasticsearchClientSettings settings, IDictionary<Type,string> indexConfig) | ||
{ | ||
foreach (var config in Utils.GetElasticConfigurationTypes()) | ||
{ | ||
var configInstance = (IElasticConfiguration)Activator.CreateInstance(config)!; | ||
configInstance.Apply(settings, indexConfig); | ||
} | ||
|
||
return settings; | ||
} | ||
|
||
public static void ConfigureAliases(this ElasticsearchClient client, IDictionary<Type,string> aliasConfig, IndexRolloverStrategy strategy) | ||
{ | ||
var namingStrategy = (IIndexNamingStrategy)Activator.CreateInstance(strategy.IndexNamingStrategy)!; | ||
|
||
foreach (var type in Utils.GetElasticDocumentTypes()) | ||
{ | ||
var aliasName = aliasConfig[type]; | ||
var indexName = namingStrategy.GenerateName(aliasName); | ||
|
||
var indexExists = client.Indices.Exists(indexName).Exists; | ||
if (indexExists) continue; | ||
|
||
var response = client.Indices.Create(indexName, c => c | ||
.Aliases(a => a.Add(aliasName, new Alias {IsWriteIndex = true}))); | ||
|
||
if (response.IsValidResponse) continue; | ||
response.TryGetOriginalException(out var exception); | ||
if(exception != null) | ||
throw exception; | ||
} | ||
} | ||
} |
Oops, something went wrong.