< Summary

Information
Class: Elsa.Hosting.Management.Services.ConfiguredApplicationInstanceNameProvider
Assembly: Elsa.Hosting.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Hosting.Management/Services/ConfiguredApplicationInstanceNameProvider.cs
Line coverage
97%
Covered lines: 39
Uncovered lines: 1
Coverable lines: 40
Total lines: 102
Line coverage: 97.5%
Branch coverage
94%
Covered branches: 34
Total branches: 36
Branch coverage: 94.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%66100%
GetName()100%11100%
ValidateConfiguredInstanceName(...)100%44100%
IsValidConfiguredInstanceName(...)92.85%161480%
IsAsciiLetterOrDigit(...)91.66%1212100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Hosting.Management/Services/ConfiguredApplicationInstanceNameProvider.cs

#LineLine coverage
 1using Elsa.Hosting.Management.Contracts;
 2using Elsa.Hosting.Management.Options;
 3using Microsoft.Extensions.Logging;
 4using Microsoft.Extensions.Options;
 5
 6namespace Elsa.Hosting.Management.Services;
 7
 8/// <summary>
 9/// Resolves the application instance name from <see cref="ApplicationInstanceOptions"/>, allowing a
 10/// stable name to be configured so that per-instance transport entities are reused across restarts
 11/// instead of accumulating. Falls back to a random name when no stable name is configured, which
 12/// preserves the previous default behaviour.
 13/// </summary>
 14/// <remarks>
 15/// Resolution order:
 16/// <list type="number">
 17/// <item><description><see cref="ApplicationInstanceOptions.InstanceName"/> when set.</description></item>
 18/// <item><description>The environment variable named by <see cref="ApplicationInstanceOptions.InstanceNameEnvironmentVa
 19/// <item><description>A randomly generated name (legacy behaviour).</description></item>
 20/// </list>
 21/// </remarks>
 22public class ConfiguredApplicationInstanceNameProvider : IApplicationInstanceNameProvider
 23{
 24    internal const int AzureServiceBusSubscriptionNameMaxLength = 50;
 25    internal const string TriggerChangeTokenSignalEndpointNameSuffix = "-elsa-trigger-change-token-signal";
 126    internal static readonly int ConfiguredInstanceNameMaxLength = AzureServiceBusSubscriptionNameMaxLength - TriggerCha
 27
 28    private readonly string _instanceName;
 29
 30    /// <summary>
 31    /// Initializes a new instance of the <see cref="ConfiguredApplicationInstanceNameProvider"/> class.
 32    /// </summary>
 1933    public ConfiguredApplicationInstanceNameProvider(
 1934        IOptions<ApplicationInstanceOptions> options,
 1935        RandomIntIdentityGenerator randomIdentityGenerator,
 1936        ILogger<ConfiguredApplicationInstanceNameProvider> logger)
 37    {
 1938        var value = options.Value;
 39
 1940        if (!string.IsNullOrWhiteSpace(value.InstanceName))
 41        {
 1142            _instanceName = ValidateConfiguredInstanceName(value.InstanceName, $"{nameof(ApplicationInstanceOptions)}.{n
 643            return;
 44        }
 45
 846        if (!string.IsNullOrWhiteSpace(value.InstanceNameEnvironmentVariable))
 47        {
 648            var environmentVariable = value.InstanceNameEnvironmentVariable.Trim();
 649            var fromEnvironment = Environment.GetEnvironmentVariable(environmentVariable);
 50
 651            if (!string.IsNullOrWhiteSpace(fromEnvironment))
 52            {
 453                _instanceName = ValidateConfiguredInstanceName(fromEnvironment, $"environment variable '{environmentVari
 354                return;
 55            }
 56
 257            logger.LogWarning(
 258                "The configured instance-name environment variable '{EnvironmentVariable}' is not set or empty. Falling 
 259                "A random name causes per-instance transport entities (such as the Azure Service Bus change-token subscr
 260                "which can accumulate until the transport's per-topic limit is reached.",
 261                environmentVariable);
 62        }
 63
 464        _instanceName = randomIdentityGenerator.GenerateId();
 465    }
 66
 67    /// <inheritdoc />
 1368    public string GetName() => _instanceName;
 69
 70    private static string ValidateConfiguredInstanceName(string value, string source)
 71    {
 1572        var instanceName = value.Trim();
 73
 1574        if (instanceName.Length <= ConfiguredInstanceNameMaxLength)
 75        {
 1376            if (IsValidConfiguredInstanceName(instanceName))
 977                return instanceName;
 78
 479            throw new InvalidOperationException(
 480                $"The configured application instance name from {source} contains invalid characters. " +
 481                "Use only letters, numbers, periods, hyphens, or underscores, and start and end the value with a letter 
 82        }
 83
 284        throw new InvalidOperationException(
 285            $"The configured application instance name from {source} is {instanceName.Length} characters long, but it mu
 286            $"The value is used to create per-instance transport entities such as '{instanceName}{TriggerChangeTokenSign
 287            "Configure a shorter stable name that is still unique for each concurrently running instance.");
 88    }
 89
 90    private static bool IsValidConfiguredInstanceName(string instanceName)
 91    {
 1392        if (instanceName.Length == 0)
 093            return false;
 94
 1395        return IsAsciiLetterOrDigit(instanceName[0])
 1396            && IsAsciiLetterOrDigit(instanceName[^1])
 7997            && instanceName.All(c => IsAsciiLetterOrDigit(c) || c is '.' or '-' or '_');
 98    }
 99
 100    private static bool IsAsciiLetterOrDigit(char value) =>
 91101        value is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '0' and <= '9';
 102}