Skip to content

Implement changes needed in the Host to decouple workers from the Host release #11111

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

Open
wants to merge 28 commits into
base: surgupta/decouple-workers-feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
987fad0
Changes for Decoupling workers implementation
surgupta-msft May 25, 2025
734b029
Added test data for unit tests
surgupta-msft May 26, 2025
cefdb92
Code cleanup and adding comments
surgupta-msft May 26, 2025
021ac3e
Code refactoring to check probing paths enabled only once
surgupta-msft May 26, 2025
36abb61
Code refactoring
surgupta-msft May 26, 2025
8929697
Tests cleanup
surgupta-msft May 26, 2025
1588711
Added test for LanguageWorkerOptionsSetup
surgupta-msft May 26, 2025
2606f37
Adding Tests for Utility class
surgupta-msft May 27, 2025
08850c9
Adding more tests
surgupta-msft May 27, 2025
10d2e52
Changes in Tests
surgupta-msft May 27, 2025
95af17e
Updating LanguageWorkerOptionsSetupTests
surgupta-msft May 27, 2025
150aaf3
Minor refactoring and code cleanup
surgupta-msft May 27, 2025
0def600
Fixing build warning
surgupta-msft May 27, 2025
cc3e044
Fixing build issue in tests
surgupta-msft May 27, 2025
26e8580
Unit test fixing
surgupta-msft May 27, 2025
9b6a945
Stylecop fixes
surgupta-msft Jun 2, 2025
e90ddda
Merge branch 'dev' into surgupta/decoupling-workers
surgupta-msft Jun 2, 2025
ee60ec4
Test data cleanup
surgupta-msft Jun 6, 2025
1495f31
Test data cleanup
surgupta-msft Jun 6, 2025
c2628bb
Merge branch 'dev' into surgupta/decoupling-workers
surgupta-msft Jun 8, 2025
4ee497b
Updated release notes
surgupta-msft Jun 9, 2025
c85ced3
Merge branch 'surgupta/decouple-workers-feature' into surgupta/decoup…
surgupta-msft Jun 12, 2025
5168090
Renaming feature name
surgupta-msft Jun 12, 2025
1ad3d14
Updated tests
surgupta-msft Jun 12, 2025
d67a254
logging update
surgupta-msft Jun 13, 2025
5844053
Logging update
surgupta-msft Jun 13, 2025
3bf3f79
Placeholder mode check
surgupta-msft Jun 14, 2025
1171fe8
Handling DefaultWorkerPath update scenario
surgupta-msft Jun 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
- Improvements to coldstart pipeline (#11102).
- Update Python Worker Version to [4.38.0](https://github.com/Azure/azure-functions-python-worker/releases/tag/4.38.0)
- Only start the Diagnostic Events flush logs timer when events are present, preventing unnecessary flush attempts (#11100).
- Implement changes needed in the Host to decouple workers from the Host release (#11111)
11 changes: 11 additions & 0 deletions src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ internal string WorkerIndexingDisabledApps
}
}

/// <summary>
/// Gets a string delimited by '|' that contains the names of the language workers available through Probing paths outside of the Host.
/// </summary>
internal string WorkersAvailableForDynamicResolution
{
get
{
return GetFeature(RpcWorkerConstants.WorkersAvailableForDynamicResolution) ?? string.Empty;
}
}

/// <summary>
/// Gets a value indicating whether Linux Log Backoff is disabled in the hosting config.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/WebJobs.Script/Environment/EnvironmentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,16 @@ public static bool IsWindowsElasticPremium(this IEnvironment environment)
return string.Equals(value, ScriptConstants.ElasticPremiumSku, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Gets a value indicating whether the application is running in a Windows App Service environment.
/// </summary>
/// <param name="environment">The environment to verify.</param>
/// <returns><see cref="true"/> if running in a Windows App Service app; otherwise, false.</returns>
public static bool IsAnyWindows(this IEnvironment environment)
{
return environment.IsWindowsAzureManagedHosting() || environment.IsWindowsConsumption() || environment.IsWindowsElasticPremium();
}

public static bool IsDynamicSku(this IEnvironment environment)
{
return environment.IsConsumptionSku() || environment.IsWindowsElasticPremium();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static class EnvironmentSettingNames
public const string AppInsightsAgent = "APPLICATIONINSIGHTS_ENABLE_AGENT";
public const string FunctionsExtensionVersion = "FUNCTIONS_EXTENSION_VERSION";
public const string FunctionWorkerRuntime = "FUNCTIONS_WORKER_RUNTIME";
public const string WorkerProbingPaths = "WORKER_PROBING_PATHS";
public const string ContainerName = "CONTAINER_NAME";
public const string WebsitePodName = "WEBSITE_POD_NAME";
public const string LegionServiceHost = "LEGION_SERVICE_HOST";
Expand Down
4 changes: 4 additions & 0 deletions src/WebJobs.Script/ScriptConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using NuGet.Versioning;

Expand Down Expand Up @@ -133,6 +134,8 @@ public static class ScriptConstants
public const string FeatureFlagDisableWebHostLogForwarding = "DisableWebHostLogForwarding";
public const string FeatureFlagDisableMergedWebHostScriptHostConfiguration = "DisableMergedConfiguration";
public const string FeatureFlagEnableWorkerIndexing = "EnableWorkerIndexing";
public const string FeatureFlagDisableDynamicWorkerResolution = "DisableDynamicWorkerResolution";
public const string FeatureFlagEnableDynamicWorkerResolution = "EnableDynamicWorkerResolution";
public const string FeatureFlagEnableDebugTracing = "EnableDebugTracing";
public const string FeatureFlagEnableProxies = "EnableProxies";
public const string FeatureFlagStrictHISModeEnabled = "StrictHISModeEnabled";
Expand Down Expand Up @@ -250,6 +253,7 @@ public static class ScriptConstants
public static readonly long DefaultMaxRequestBodySize = 104857600;

public static readonly ImmutableArray<string> SystemLogCategoryPrefixes = ImmutableArray.Create("Microsoft.Azure.WebJobs.", "Function.", "Worker.", "Host.");
public static readonly HashSet<string> HostCapabilities = [];

public static readonly string FunctionMetadataDirectTypeKey = "DirectType";
public static readonly string LiveLogsSessionAIKey = "#AzFuncLiveLogsSessionId";
Expand Down
35 changes: 35 additions & 0 deletions src/WebJobs.Script/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Microsoft.Azure.WebJobs.Script.Models;
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
Expand Down Expand Up @@ -1065,6 +1066,35 @@ public static bool CanWorkerIndex(IEnumerable<RpcWorkerConfig> workerConfigs, IE
return workerIndexingEnabled && workerIndexingAvailable;
}

// Dynamic Worker Resolution can be enabled or disabled via feature flags or hosting config options. Feature flags take precedence over hosting config options.
// Users can enable or disable worker resolution via setting the appropriate feature flags.
// Worker resolution can also be enabled for specific workers at stamp level via the hosting config options.
public static bool IsDynamicWorkerResolutionEnabled(IEnvironment environment, HashSet<string> workersAvailableForResolutionViaHostingConfig)
{
bool isDynamicWorkerResolutionDisabled = FeatureFlags.IsEnabled(ScriptConstants.FeatureFlagDisableDynamicWorkerResolution, environment);

if (isDynamicWorkerResolutionDisabled)
{
return false;
}

bool isDynamicWorkerResolutionEnabled = FeatureFlags.IsEnabled(ScriptConstants.FeatureFlagEnableDynamicWorkerResolution, environment);

if (isDynamicWorkerResolutionEnabled)
{
return true;
}

string workerRuntime = environment.GetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName);

if (!environment.IsMultiLanguageRuntimeEnvironment() && !string.IsNullOrWhiteSpace(workerRuntime))
{
return workersAvailableForResolutionViaHostingConfig?.Contains(workerRuntime) ?? false;
}

return workersAvailableForResolutionViaHostingConfig?.Any() ?? false;
}

public static void LogAutorestGeneratedJsonIfExists(string rootScriptPath, ILogger logger)
{
string autorestGeneratedJsonPath = Path.Combine(rootScriptPath, ScriptConstants.AutorestGeenratedMetadataFileName);
Expand Down Expand Up @@ -1127,6 +1157,11 @@ public static FunctionAppContentEditingState GetFunctionAppContentEditingState(I
}
}

public static string GetPlatformReleaseChannel(IEnvironment environment)
{
return environment.GetEnvironmentVariable(EnvironmentSettingNames.AntaresPlatformReleaseChannel) ?? ScriptConstants.LatestPlatformChannelNameUpper;
}

public static bool TryReadAsBool(IDictionary<string, object> properties, string propertyKey, out bool result)
{
if (properties.TryGetValue(propertyKey, out object valueObject))
Expand Down
2 changes: 1 addition & 1 deletion src/WebJobs.Script/Workers/Http/HttpWorkerDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class HttpWorkerDescription : WorkerDescription

public override bool UseStdErrorStreamForErrorsOnly { get; set; } = true;

public override void ApplyDefaultsAndValidate(string inputWorkerDirectory, ILogger logger)
public override void ApplyDefaultsAndValidate(string inputWorkerDirectory, ILogger logger, bool probingPathEnabled = false, HashSet<string> workersAvailableForResolutionViaHostingConfig = null)
{
if (inputWorkerDirectory == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public abstract class WorkerDescription
/// </summary>
public bool? IsDisabled { get; set; }

public abstract void ApplyDefaultsAndValidate(string workerDirectory, ILogger logger);
public abstract void ApplyDefaultsAndValidate(string workerDirectory, ILogger logger, bool probingPathEnabled = false, HashSet<string> workersAvailableForResolutionViaHostingConfig = null);

internal void ThrowIfFileNotExists(string inputFile, string paramName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using Microsoft.Azure.WebJobs.Script.Config;
using Microsoft.Azure.WebJobs.Script.Diagnostics;
using Microsoft.Azure.WebJobs.Script.Workers.Profiles;
using Microsoft.Azure.WebJobs.Script.Workers.Rpc.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand All @@ -15,19 +21,22 @@ namespace Microsoft.Azure.WebJobs.Script.Workers.Rpc
{
internal class LanguageWorkerOptionsSetup : IConfigureOptions<LanguageWorkerOptions>
{
private const string _windowsWorkerProbingPath = "C:\\home\\SiteExtensions\\workers"; // Harcoded site extensions path for Windows until Antares sets it as an Environment variable.
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
private readonly IEnvironment _environment;
private readonly IMetricsLogger _metricsLogger;
private readonly IWorkerProfileManager _workerProfileManager;
private readonly IScriptHostManager _scriptHostManager;
private readonly IOptions<FunctionsHostingConfigOptions> _functionsHostingConfigOptions;

public LanguageWorkerOptionsSetup(IConfiguration configuration,
ILoggerFactory loggerFactory,
IEnvironment environment,
IMetricsLogger metricsLogger,
IWorkerProfileManager workerProfileManager,
IScriptHostManager scriptHostManager)
IScriptHostManager scriptHostManager,
IOptions<FunctionsHostingConfigOptions> functionsHostingConfigOptions)
{
if (loggerFactory is null)
{
Expand All @@ -39,6 +48,7 @@ public LanguageWorkerOptionsSetup(IConfiguration configuration,
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
_metricsLogger = metricsLogger ?? throw new ArgumentNullException(nameof(metricsLogger));
_workerProfileManager = workerProfileManager ?? throw new ArgumentNullException(nameof(workerProfileManager));
_functionsHostingConfigOptions = functionsHostingConfigOptions ?? throw new ArgumentNullException(nameof(functionsHostingConfigOptions));

_logger = loggerFactory.CreateLogger("Host.LanguageWorkerConfig");
}
Expand Down Expand Up @@ -72,9 +82,50 @@ public void Configure(LanguageWorkerOptions options)
}
}

var configFactory = new RpcWorkerConfigFactory(configuration, _logger, SystemRuntimeInformation.Instance, _environment, _metricsLogger, _workerProfileManager);
HashSet<string> workers = GetWorkersAvailableForResolutionViaHostingConfig();
bool dynamicWorkerResolutionEnabled = Utility.IsDynamicWorkerResolutionEnabled(_environment, workers);
List<string> probingPaths = null;

if (dynamicWorkerResolutionEnabled)
{
probingPaths = GetWorkerProbingPaths();
}

var workerConfigurationResolver = new WorkerConfigurationResolver(configuration, _logger, _environment, _workerProfileManager, workers);
var configFactory = new RpcWorkerConfigFactory(configuration, _logger, SystemRuntimeInformation.Instance, _environment, _metricsLogger, _workerProfileManager, workerConfigurationResolver, dynamicWorkerResolutionEnabled, probingPaths, workers);
options.WorkerConfigs = configFactory.GetConfigs();
}

internal HashSet<string> GetWorkersAvailableForResolutionViaHostingConfig()
{
return _functionsHostingConfigOptions.Value
?.WorkersAvailableForDynamicResolution
?.ToLowerInvariant()
.Split("|", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.ToHashSet();
}

internal List<string> GetWorkerProbingPaths()
{
var probingPaths = new List<string>();

// If Environment variable is set, read probing paths from Environment
string probingPathsEnvValue = _environment.GetEnvironmentVariableOrDefault(EnvironmentSettingNames.WorkerProbingPaths, null);

if (!string.IsNullOrEmpty(probingPathsEnvValue))
{
probingPaths = probingPathsEnvValue.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList();
}
else
{
if (_environment.IsAnyWindows())
{
probingPaths.Add(_windowsWorkerProbingPath);
}
}

return probingPaths;
}
}

/// <summary>
Expand All @@ -100,4 +151,4 @@ public void PostConfigure(string name, LanguageWorkerOptions options)
logger.LogInformation(message);
}
}
}
}
Loading