diff --git a/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedContext.cs b/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedContext.cs
index 9e3a9b37fb3..032352e33c7 100644
--- a/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedContext.cs
+++ b/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedContext.cs
@@ -38,8 +38,6 @@ public DistributedContext(ShellContext context)
public IDistributedCache DistributedCache { get; }
- public bool HasIsolatedConfiguration { get; internal set; }
-
public DistributedContext Acquire()
{
// Don't acquire a released context.
diff --git a/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedShellHostedService.cs b/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedShellHostedService.cs
index 406222f4fde..122976a8f37 100644
--- a/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedShellHostedService.cs
+++ b/src/OrchardCore/OrchardCore/Shell/Distributed/DistributedShellHostedService.cs
@@ -4,6 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OrchardCore.Environment.Shell.Builders;
@@ -43,7 +44,7 @@ internal class DistributedShellHostedService : BackgroundService
private DistributedContext _context;
private DateTime _busyStartTime;
- private bool _terminated;
+ private bool _initialized;
public DistributedShellHostedService(
IShellHost shellHost,
@@ -58,7 +59,6 @@ public DistributedShellHostedService(
_shellRemovingManager = shellRemovingManager;
_logger = logger;
- shellHost.LoadingAsync += LoadingAsync;
shellHost.ReleasingAsync += ReleasingAsync;
shellHost.ReloadingAsync += ReloadingAsync;
shellHost.RemovingAsync += RemovingAsync;
@@ -139,6 +139,17 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
continue;
}
+ // Initialize the service if not yet done by using the distributed cache.
+ try
+ {
+ await EnsureInitializedAsync(distributedCache);
+ }
+ catch (Exception ex) when (!ex.IsFatal())
+ {
+ // Get the next idle time before retrying to use the distributed cache.
+ idleTime = NextIdleTimeBeforeRetry(idleTime, ex);
+ }
+
// Try to retrieve the tenant changed global identifier from the distributed cache.
string shellChangedId;
try
@@ -307,7 +318,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}
}
- _terminated = true;
+ _initialized = false;
+
+ _shellHost.ReleasingAsync -= ReleasingAsync;
+ _shellHost.ReloadingAsync -= ReloadingAsync;
+ _shellHost.RemovingAsync -= RemovingAsync;
if (_context is not null)
{
@@ -318,41 +333,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
}
///
- /// Called before loading all tenants to initialize the local shell identifiers from the distributed cache.
+ /// Initialize the local shell identifiers from the distributed cache.
///
- public async Task LoadingAsync()
+ public async Task EnsureInitializedAsync(IDistributedCache distributedCache)
{
- if (_terminated)
- {
- return;
- }
-
- // Load a first isolated configuration as the default context it is not yet initialized.
- var defaultSettings = (await _shellSettingsManager
- .LoadSettingsAsync(ShellSettings.DefaultShellName))
- .AsDisposable();
-
- // If there is no default tenant or it is not running, nothing to do.
- if (!defaultSettings.IsRunning())
- {
- defaultSettings.Dispose();
- return;
- }
-
- // Create a distributed context based on the first isolated configuration.
- var context = _context = await CreateDistributedContextAsync(defaultSettings);
- if (context is null)
- {
- defaultSettings.Dispose();
- return;
- }
-
- // Mark the context as using the first isolated configuration.
- context.HasIsolatedConfiguration = true;
-
- // If the required distributed features are not enabled, nothing to do.
- var distributedCache = context.DistributedCache;
- if (distributedCache is null)
+ if (_initialized)
{
return;
}
@@ -389,10 +374,12 @@ public async Task LoadingAsync()
// Keep in sync the tenant global identifiers.
_shellChangedId = shellChangedId;
_shellCountChangedId = shellCountChangedId;
+
+ _initialized = true;
}
catch (Exception ex) when (!ex.IsFatal())
{
- _logger.LogError(ex, "Unable to read the distributed cache before loading all tenants.");
+ _logger.LogError(ex, "Unable to read the distributed cache while initializing the tenant identifiers.");
}
}
@@ -401,7 +388,7 @@ public async Task LoadingAsync()
///
public async Task ReleasingAsync(string name)
{
- if (_terminated)
+ if (!_initialized)
{
return;
}
@@ -452,7 +439,7 @@ public async Task ReleasingAsync(string name)
///
public async Task ReloadingAsync(string name)
{
- if (_terminated)
+ if (!_initialized)
{
return;
}
@@ -467,13 +454,6 @@ public async Task ReloadingAsync(string name)
// Acquire the distributed context or create a new one if not yet built.
await using var context = await AcquireOrCreateDistributedContextAsync(defaultContext);
- // If the context still use the first isolated configuration.
- if (context is not null && context.HasIsolatedConfiguration)
- {
- // Reset the serial number so that a new context will be built.
- context.Context.Blueprint.Descriptor.SerialNumber = 0;
- }
-
// If the required distributed features are not enabled, nothing to do.
var distributedCache = context?.DistributedCache;
if (distributedCache is null)
@@ -518,7 +498,7 @@ public async Task ReloadingAsync(string name)
public async Task RemovingAsync(string name)
{
// The 'Default' tenant can't be removed.
- if (_terminated || name.IsDefaultShellName())
+ if (!_initialized || name.IsDefaultShellName())
{
return;
}
@@ -562,14 +542,21 @@ public async Task RemovingAsync(string name)
}
}
- private static string ReleaseIdKey(string name) => name + ReleaseIdKeySuffix;
- private static string ReloadIdKey(string name) => name + ReloadIdKeySuffix;
+ private static string ReleaseIdKey(string name) => $"{name}{ReleaseIdKeySuffix}";
+ private static string ReloadIdKey(string name) => $"{name}{ReloadIdKeySuffix}";
///
/// Creates a distributed context based on the default tenant context.
///
private async Task CreateDistributedContextAsync(ShellContext defaultContext)
{
+ // Check if the distributed shell feature is enabled.
+ if (!HasDistributedShellFeature(defaultContext))
+ {
+ // Nothing to create.
+ return null;
+ }
+
// Get the default tenant descriptor.
var descriptor = await GetDefaultShellDescriptorAsync(defaultContext);
@@ -601,21 +588,6 @@ private async Task CreateDistributedContextAsync(ShellSettin
}
}
- ///
- /// Creates a distributed context based on the default tenant settings.
- ///
- private async Task CreateDistributedContextAsync(ShellSettings defaultSettings)
- {
- try
- {
- return new DistributedContext(await _shellContextFactory.CreateShellContextAsync(defaultSettings));
- }
- catch
- {
- return null;
- }
- }
-
///
/// Gets the default tenant descriptor.
///
@@ -679,6 +651,13 @@ private async Task GetOrCreateDistributedContextAsync(ShellC
///
private async Task ReuseOrCreateDistributedContextAsync(ShellContext defaultContext)
{
+ // Check if the distributed shell feature is enabled.
+ if (!HasDistributedShellFeature(defaultContext))
+ {
+ // Nothing to create.
+ return null;
+ }
+
// If no context.
if (_context is null)
{
@@ -698,7 +677,7 @@ private async Task ReuseOrCreateDistributedContextAsync(Shel
// If no descriptor.
if (descriptor is null)
- {
+ {
// Nothing to create.
return null;
}
@@ -731,6 +710,25 @@ private Task AcquireOrCreateDistributedContextAsync(ShellCon
return Task.FromResult(distributedContext);
}
+ ///
+ /// Whether the default context has the distributed shell feature enabled or not.
+ ///
+ private static bool HasDistributedShellFeature(ShellContext defaultContext)
+ {
+ try
+ {
+ if (defaultContext.ServiceProvider?.GetService() is not null)
+ {
+ return true;
+ }
+ }
+ catch
+ {
+ }
+
+ return false;
+ }
+
///
/// Gets the next idle time before retrying to read the distributed cache.
///