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

OFFI-109: Delete already existing elasticsearch indexes related to the tenant #130

Merged
merged 15 commits into from
Sep 12, 2024
2 changes: 2 additions & 0 deletions Lombiq.Hosting.Tenants.Maintenance/Constants/FeatureNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ public static class FeatureNames
public const string AddSiteOwnerPermissionToRole = Maintenance + "." + nameof(AddSiteOwnerPermissionToRole);
public const string RemoveUsers = Maintenance + "." + nameof(RemoveUsers);
public const string ChangeUserSensitiveContent = Maintenance + "." + nameof(ChangeUserSensitiveContent);
public const string DeleteOrRebuildElasticsearchIndices = Maintenance + "." + nameof(DeleteOrRebuildElasticsearchIndices);
public const string DeleteElasticsearchIndicesBeforeSetup = Maintenance + "." + nameof(DeleteElasticsearchIndicesBeforeSetup);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<PackageReference Include="OrchardCore.ContentManagement" Version="1.8.0" />
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" Version="1.8.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="1.8.0" />
<PackageReference Include="OrchardCore.Search.Elasticsearch.Core" Version="1.8.0" />
<PackageReference Include="OrchardCore.Settings" Version="1.8.0" />
<PackageReference Include="OrchardCore.Users.Abstractions" Version="1.8.0" />
<PackageReference Include="OrchardCore.Users.Core" Version="1.8.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Lombiq.HelpfulLibraries.OrchardCore.Mvc;
using Lombiq.Hosting.Tenants.Maintenance.Constants;
using Lombiq.Hosting.Tenants.Maintenance.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Modules;
Expand All @@ -17,10 +17,9 @@ public Startup(IShellConfiguration shellConfiguration) =>

public override void ConfigureServices(IServiceCollection services)
{
var options = new AddSiteOwnerPermissionToRoleMaintenanceOptions();
var configSection = _shellConfiguration.GetSection("Lombiq_Hosting_Tenants_Maintenance:AddSiteOwnerPermissionToRole");
configSection.Bind(options);
services.Configure<AddSiteOwnerPermissionToRoleMaintenanceOptions>(configSection);
services.BindAndConfigureSection<AddSiteOwnerPermissionToRoleMaintenanceOptions>(
_shellConfiguration,
"Lombiq_Hosting_Tenants_Maintenance:AddSiteOwnerPermissionToRole");

services.AddScoped<IMaintenanceProvider, AddSiteOwnerPermissionToRoleMaintenanceProvider>();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Lombiq.HelpfulLibraries.OrchardCore.Mvc;
using Lombiq.Hosting.Tenants.Maintenance.Constants;
using Lombiq.Hosting.Tenants.Maintenance.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Modules;
Expand All @@ -17,11 +17,9 @@ public Startup(IShellConfiguration shellConfiguration) =>

public override void ConfigureServices(IServiceCollection services)
{
var options = new ChangeUserSensitiveContentMaintenanceOptions();
var configSection = _shellConfiguration
.GetSection("Lombiq_Hosting_Tenants_Maintenance:ChangeUserSensitiveContent");
configSection.Bind(options);
services.Configure<ChangeUserSensitiveContentMaintenanceOptions>(configSection);
services.BindAndConfigureSection<ChangeUserSensitiveContentMaintenanceOptions>(
_shellConfiguration,
"Lombiq_Hosting_Tenants_Maintenance:ChangeUserSensitiveContent");

services.AddScoped<IMaintenanceProvider, ChangeUserSensitiveContentMaintenanceProvider>();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Lombiq.Hosting.Tenants.Maintenance.Extensions;
using Lombiq.Hosting.Tenants.Maintenance.Models;
using Lombiq.Hosting.Tenants.Maintenance.Services;
using Microsoft.Extensions.Options;
using OrchardCore.Search.Elasticsearch.Core.Services;
using System.Threading.Tasks;

namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.ElasticsearchIndices;

public class DeleteElasticsearchIndicesMaintenanceProvider : MaintenanceProviderBase
{
private readonly IOptions<ElasticsearchIndicesMaintenanceOptions> _options;
private readonly ElasticIndexManager _elasticIndexManager;

public DeleteElasticsearchIndicesMaintenanceProvider(
IOptions<ElasticsearchIndicesMaintenanceOptions> options,
ElasticIndexManager elasticIndexManager)
{
_options = options;
_elasticIndexManager = elasticIndexManager;
}

public override Task<bool> ShouldExecuteAsync(MaintenanceTaskExecutionContext context) =>
Task.FromResult(
_options.Value.DeleteMaintenanceIsEnabled &&
!context.WasLatestExecutionSuccessful());

public override Task ExecuteAsync(MaintenanceTaskExecutionContext context) =>
// Delete all tenant specific indexes in Elasticsearch.
_elasticIndexManager.DeleteIndex("*");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Environment.Shell;
using OrchardCore.Locking.Distributed;
using OrchardCore.Search.Elasticsearch.Core.Services;
using System;
using System.Net;
using System.Threading.Tasks;

namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.ElasticsearchIndices;

public class DeleteElasticsearchIndicesMiddleware
{
private readonly RequestDelegate _next;

private readonly ShellSettings _shellSettings;

private readonly IShellSettingsManager _shellSettingsManager;

private readonly IDistributedLock _distributedLock;

public DeleteElasticsearchIndicesMiddleware(
RequestDelegate next,
ShellSettings shellSettings,
IShellSettingsManager shellSettingsManager,
IDistributedLock distributedLock)
{
_next = next;
_shellSettings = shellSettings;
_shellSettingsManager = shellSettingsManager;
_distributedLock = distributedLock;
}

public async Task InvokeAsync(HttpContext httpContext)
{
if (httpContext.Request.Method != WebRequestMethods.Http.Get)
{
await _next.Invoke(httpContext);
return;
}

if (await InvokeNextIfUninitializedAsync(_shellSettings, httpContext)) return;

// Try to acquire a lock before starting installation
var (locker, locked) = await _distributedLock.TryAcquireLockAsync(
"ELASTICSEARCH_INDICES_DELETION",
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1));

if (!locked)
{
throw new TimeoutException($"Failed to acquire an Elasticsearch indices deletion lock for the tenant: {_shellSettings.Name}");
}

await using var acquiredLock = locker;

// Check if the tenant was installed by another instance.
if (await InvokeNextIfUninitializedAsync(_shellSettings, httpContext)) return;

using var settings = (await _shellSettingsManager.LoadSettingsAsync(_shellSettings.Name)).AsDisposable();

// If the tenant was initialized by another instance, then skip again.
if (await InvokeNextIfUninitializedAsync(settings, httpContext)) return;

var elasticIndexManager = httpContext.RequestServices.GetRequiredService<ElasticIndexManager>();

// Delete all tenant specific indexes in Elasticsearch.
await elasticIndexManager.DeleteIndex("*");

await _next.Invoke(httpContext);
}

private async Task<bool> InvokeNextIfUninitializedAsync(ShellSettings shellSettings, HttpContext httpContext)
{
if (shellSettings.IsUninitialized())
{
return false;
}

await _next.Invoke(httpContext);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.ElasticsearchIndices;

public class ElasticsearchIndicesMaintenanceOptions
{
public bool DeleteMaintenanceIsEnabled { get; set; }
public bool RebuildMaintenanceIsEnabled { get; set; }
public bool BeforeSetupMiddlewareIsEnabled { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Lombiq.Hosting.Tenants.Maintenance.Extensions;
using Lombiq.Hosting.Tenants.Maintenance.Models;
using Lombiq.Hosting.Tenants.Maintenance.Services;
using Microsoft.Extensions.Options;
using OrchardCore.Search.Elasticsearch.Core.Services;
using System.Threading.Tasks;

namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.ElasticsearchIndices;

public class RebuildElasticsearchIndicesMaintenanceProvider : MaintenanceProviderBase
{
private readonly IOptions<ElasticsearchIndicesMaintenanceOptions> _options;
private readonly ElasticIndexingService _elasticIndexingService;
private readonly ElasticIndexSettingsService _elasticIndexSettingsService;

public RebuildElasticsearchIndicesMaintenanceProvider(
IOptions<ElasticsearchIndicesMaintenanceOptions> options,
ElasticIndexingService elasticIndexingService,
ElasticIndexSettingsService elasticIndexSettingsService)
{
_options = options;
_elasticIndexingService = elasticIndexingService;
_elasticIndexSettingsService = elasticIndexSettingsService;
}

public override Task<bool> ShouldExecuteAsync(MaintenanceTaskExecutionContext context) =>
Task.FromResult(
_options.Value.RebuildMaintenanceIsEnabled &&
!context.WasLatestExecutionSuccessful());

public override async Task ExecuteAsync(MaintenanceTaskExecutionContext context)
{
var settings = await _elasticIndexSettingsService.GetSettingsAsync();
foreach (var setting in settings)
{
await _elasticIndexingService.RebuildIndexAsync(setting);

if (setting.QueryAnalyzerName != setting.AnalyzerName)
{
// Query Analyzer may be different until the index is rebuilt.
// Since the index is rebuilt, lets make sure we query using the same analyzer.
setting.QueryAnalyzerName = setting.AnalyzerName;

await _elasticIndexSettingsService.UpdateIndexAsync(setting);
}

await _elasticIndexingService.ProcessContentItemsAsync(setting.IndexName);
}
}
}
Loading