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

An invalid host.json file in combination with a HostInitializationError can cause an endless ScriptHost restart loop #10452

Open
cjaliaga opened this issue Sep 6, 2024 · 0 comments

Comments

@cjaliaga
Copy link
Member

cjaliaga commented Sep 6, 2024

An invalid host.json file in combination with a HostInitializationError can cause an endless ScriptHost restart loop.

We discovered this issue while addressing misconfigurations in applications during a recent release. #10439 reintroduced temporary support for the previous behavior, which reduces the frequency of this issue but doesn't fully resolve it. As this fallback is only temporary and will be removed, it is essential to address the root cause before the fallback behavior is disabled.

Conditions to reproduce

  • Invalid host.json, for example a host.json file missing the version property:
    "version": "2.0",
  • Error initializing the Host. For example a situation that throws 'Did not find functions with language [dotnet-isolated].'

WebJobsScriptHostService.UnsynchronizedStartHostAsync attempts:

1. First attempt, on this one we try to load host.json as usual

startupMode = JobHostStartupMode.Normal
skipHostJsonConfiguration = false

Since the host.json is invalid, we will throw a HostConfigurationException trying to build the host:

// If we're in a non-transient error state or offline, skip host initialization
bool skipJobHostStartup = isOffline || hasNonTransientErrors;
bool skipHostJsonConfiguration = startupMode == JobHostStartupMode.HandlingConfigurationParsingError;
string functionsExtensionVersion = _environment.GetFunctionsExtensionVersion();
_logger.Building(functionsExtensionVersion, skipJobHostStartup, skipHostJsonConfiguration, activeOperation.Id);
using (_metricsLogger.LatencyEvent(MetricEventNames.ScriptHostManagerBuildScriptHost))
{
localHost = BuildHost(skipJobHostStartup, skipHostJsonConfiguration);
}

2. On this next attempt, we will be handling the Host Configuration Error, skipping the step of parsing the host.json:

startupMode = JobHostStartupMode.HandlingConfigurationParsingError
skipJobHostStartup = false
skipHostJsonConfiguration = true 

We will be able to build the host:

// If we're in a non-transient error state or offline, skip host initialization
bool skipJobHostStartup = isOffline || hasNonTransientErrors;
bool skipHostJsonConfiguration = startupMode == JobHostStartupMode.HandlingConfigurationParsingError;
string functionsExtensionVersion = _environment.GetFunctionsExtensionVersion();
_logger.Building(functionsExtensionVersion, skipJobHostStartup, skipHostJsonConfiguration, activeOperation.Id);
using (_metricsLogger.LatencyEvent(MetricEventNames.ScriptHostManagerBuildScriptHost))
{
localHost = BuildHost(skipJobHostStartup, skipHostJsonConfiguration);
}

However, we won't be able to start the host and we will throw a HostInitializationException here:

await localHost.StartAsync(currentCancellationToken);

3. On this attempt we're handling an initialization error:

startupMode = JobHostStartupMode.HandlingInitializationError
skipJobHostStartup = true
skipHostJsonConfiguration = false

Now we will skip job host startup, but since the host.json is still invalid, we will throw a HostConfigurationException again trying to build the host:

// If we're in a non-transient error state or offline, skip host initialization
bool skipJobHostStartup = isOffline || hasNonTransientErrors;
bool skipHostJsonConfiguration = startupMode == JobHostStartupMode.HandlingConfigurationParsingError;
string functionsExtensionVersion = _environment.GetFunctionsExtensionVersion();
_logger.Building(functionsExtensionVersion, skipJobHostStartup, skipHostJsonConfiguration, activeOperation.Id);
using (_metricsLogger.LatencyEvent(MetricEventNames.ScriptHostManagerBuildScriptHost))
{
localHost = BuildHost(skipJobHostStartup, skipHostJsonConfiguration);
}

4. This attempt will be exactly as attempt 2
5. This attempt will be exactly as attempt 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant