in src/WebJobs.Script/Workers/Rpc/Configuration/RpcWorkerConfigFactory.cs [117:212]
internal void AddProvider(string workerDir)
{
using (_metricsLogger.LatencyEvent(string.Format(MetricEventNames.AddProvider, workerDir)))
{
try
{
// After specialization, load worker config only for the specified runtime unless it's a multi-language app.
if (!string.IsNullOrWhiteSpace(_workerRuntime) && !_environment.IsPlaceholderModeEnabled() && !_environment.IsMultiLanguageRuntimeEnvironment())
{
string workerRuntime = Path.GetFileName(workerDir);
// Only skip worker directories that don't match the current runtime.
// Do not skip non-worker directories like the function app payload directory
if (!workerRuntime.Equals(_workerRuntime, StringComparison.OrdinalIgnoreCase) && workerDir.StartsWith(WorkersDirPath))
{
return;
}
}
string workerConfigPath = Path.Combine(workerDir, RpcWorkerConstants.WorkerConfigFileName);
if (!File.Exists(workerConfigPath))
{
_logger.LogDebug("Did not find worker config file at: {workerConfigPath}", workerConfigPath);
return;
}
_logger.LogDebug("Found worker config: {workerConfigPath}", workerConfigPath);
var workerConfig = GetWorkerConfigJsonElement(workerConfigPath);
var workerDescriptionElement = workerConfig.GetProperty(WorkerConstants.WorkerDescription);
var workerDescription = workerDescriptionElement.Deserialize<RpcWorkerDescription>(_jsonSerializerOptions);
workerDescription.WorkerDirectory = workerDir;
// Read the profiles from worker description and load the profile for which the conditions match
if (workerConfig.TryGetProperty(WorkerConstants.WorkerDescriptionProfiles, out var profiles))
{
List<WorkerDescriptionProfile> workerDescriptionProfiles = ReadWorkerDescriptionProfiles(profiles);
if (workerDescriptionProfiles.Count > 0)
{
_profileManager.SetWorkerDescriptionProfiles(workerDescriptionProfiles, workerDescription.Language);
_profileManager.LoadWorkerDescriptionFromProfiles(workerDescription, out workerDescription);
}
}
// Check if any app settings are provided for that language
var languageSection = _config.GetSection($"{RpcWorkerConstants.LanguageWorkersSectionName}:{workerDescription.Language}");
workerDescription.Arguments ??= new List<string>();
GetWorkerDescriptionFromAppSettings(workerDescription, languageSection);
AddArgumentsFromAppSettings(workerDescription, languageSection);
// Validate workerDescription
workerDescription.ApplyDefaultsAndValidate(Directory.GetCurrentDirectory(), _logger);
if (workerDescription.IsDisabled == true)
{
_logger.LogInformation("Skipping WorkerConfig for stack: {language} since it is disabled.", workerDescription.Language);
return;
}
if (ShouldAddWorkerConfig(workerDescription.Language))
{
workerDescription.FormatWorkerPathIfNeeded(_systemRuntimeInformation, _environment, _logger);
workerDescription.FormatWorkingDirectoryIfNeeded();
workerDescription.FormatArgumentsIfNeeded(_logger);
workerDescription.ThrowIfFileNotExists(workerDescription.DefaultWorkerPath, nameof(workerDescription.DefaultWorkerPath));
workerDescription.ExpandEnvironmentVariables();
WorkerProcessCountOptions workerProcessCount = GetWorkerProcessCount(workerConfig);
var arguments = new WorkerProcessArguments()
{
ExecutablePath = workerDescription.DefaultExecutablePath,
WorkerPath = workerDescription.DefaultWorkerPath
};
arguments.ExecutableArguments.AddRange(workerDescription.Arguments);
var rpcWorkerConfig = new RpcWorkerConfig()
{
Description = workerDescription,
Arguments = arguments,
CountOptions = workerProcessCount,
};
_workerDescriptionDictionary[workerDescription.Language] = rpcWorkerConfig;
ReadLanguageWorkerFile(arguments.WorkerPath);
_logger.LogDebug("Added WorkerConfig for language: {language}", workerDescription.Language);
}
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogError(ex, "Failed to initialize worker provider for: {workerDir}", workerDir);
}
}
}