Skip to content

Commit 9c28f10

Browse files
authored
Configure CV2 FunctionTimeout defaulting and validation (#9252)
1 parent b4466aa commit 9c28f10

File tree

2 files changed

+53
-84
lines changed

2 files changed

+53
-84
lines changed

src/WebJobs.Script/Config/ScriptJobHostOptionsSetup.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using Microsoft.Extensions.Configuration;
6-
using Microsoft.Extensions.Logging.Abstractions;
76
using Microsoft.Extensions.Options;
87

98
namespace Microsoft.Azure.WebJobs.Script.Configuration
@@ -15,7 +14,7 @@ internal class ScriptJobHostOptionsSetup : IConfigureOptions<ScriptJobHostOption
1514
private readonly IOptions<ScriptApplicationHostOptions> _applicationHostOptions;
1615

1716
internal static readonly TimeSpan MinFunctionTimeout = TimeSpan.FromSeconds(1);
18-
internal static readonly TimeSpan DefaultFunctionTimeoutDynamic = TimeSpan.FromMinutes(5);
17+
internal static readonly TimeSpan DefaultConsumptionFunctionTimeout = TimeSpan.FromMinutes(5);
1918
internal static readonly TimeSpan MaxFunctionTimeoutDynamic = TimeSpan.FromMinutes(10);
2019
internal static readonly TimeSpan DefaultFunctionTimeout = TimeSpan.FromMinutes(30);
2120

@@ -79,11 +78,11 @@ private void ConfigureFunctionTimeout(ScriptJobHostOptions options)
7978
{
8079
if (options.FunctionTimeout == null)
8180
{
82-
options.FunctionTimeout = _environment.IsConsumptionSku() ? DefaultFunctionTimeoutDynamic : DefaultFunctionTimeout;
81+
options.FunctionTimeout = (_environment.IsConsumptionSku() && !_environment.IsFlexConsumptionSku()) ? DefaultConsumptionFunctionTimeout : DefaultFunctionTimeout;
8382
}
84-
else if (!_environment.IsConsumptionSku() && TimeSpan.Compare(options.FunctionTimeout.Value, TimeSpan.FromDays(-1)) == 0)
83+
else if (SkuSupportsUnboundedTimeout(_environment) && TimeSpan.Compare(options.FunctionTimeout.Value, TimeSpan.FromDays(-1)) == 0)
8584
{
86-
// If a value of -1 is specified on a dedicated host, it should result in an infinite timeout
85+
// A value of -1 is translated to an infinite timeout for skus that support it
8786
options.FunctionTimeout = null;
8887
}
8988
else
@@ -96,17 +95,25 @@ private void ValidateTimeoutValue(ScriptJobHostOptions options, TimeSpan? timeou
9695
{
9796
if (timeoutValue != null)
9897
{
98+
// determine the maximum allowed timeout based on SKU
9999
var maxTimeout = TimeSpan.MaxValue;
100-
if (_environment.IsConsumptionSku())
100+
if (!SkuSupportsUnboundedTimeout(_environment))
101101
{
102102
maxTimeout = MaxFunctionTimeoutDynamic;
103103
}
104+
105+
// verify the configured timeout is in bounds
104106
if (timeoutValue < MinFunctionTimeout || timeoutValue > maxTimeout)
105107
{
106108
string message = $"{nameof(options.FunctionTimeout)} must be greater than {MinFunctionTimeout} and less than {maxTimeout}.";
107109
throw new ArgumentException(message);
108110
}
109111
}
110112
}
113+
114+
private bool SkuSupportsUnboundedTimeout(IEnvironment environment)
115+
{
116+
return !environment.IsConsumptionSku() || environment.IsFlexConsumptionSku();
117+
}
111118
}
112119
}

test/WebJobs.Script.Tests/Configuration/ScriptJobHostOptionsSetupTests.cs

Lines changed: 40 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -76,72 +76,40 @@ public void Configure_FileWatching()
7676
Assert.Contains("mySecondFile.ext", options.WatchFiles);
7777
}
7878

79-
[Fact(Skip = "ApplyConfiguration no longer exists. Validate logic (moved to HostJsonFileConfigurationSource)")]
80-
public void Configure_AllowPartialHostStartup()
81-
{
82-
//var settings = new Dictionary<string, string>
83-
//{
84-
// { ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "fileWatchingEnabled"), "true" }
85-
//};
86-
87-
//var options = new ScriptHostOptions();
88-
89-
//// Validate default (this should be in another test - migrated here for now)
90-
//Assert.True(options.FileWatchingEnabled);
91-
92-
//Assert.True(options.HostConfig.AllowPartialHostStartup);
93-
94-
//// explicit setting can override our default
95-
//scriptConfig = new ScriptHostConfiguration();
96-
//config["allowPartialHostStartup"] = new JValue(true);
97-
//ScriptHost.ApplyConfiguration(config, scriptConfig);
98-
//Assert.True(scriptConfig.HostConfig.AllowPartialHostStartup);
99-
100-
//// explicit setting can override our default
101-
//scriptConfig = new ScriptHostConfiguration();
102-
//config["allowPartialHostStartup"] = new JValue(false);
103-
//ScriptHost.ApplyConfiguration(config, scriptConfig);
104-
//Assert.False(scriptConfig.HostConfig.AllowPartialHostStartup);
105-
}
106-
10779
[Theory]
108-
[InlineData(true, false)]
109-
[InlineData(false, true)]
110-
[InlineData(true, true)]
111-
public void Configure_AppliesDefaults_IfDynamic(bool isLinuxConsumption, bool isWindowsConsumption)
80+
[InlineData(ScriptConstants.DynamicSku, false)]
81+
[InlineData(ScriptConstants.DynamicSku, true)]
82+
[InlineData("", true)]
83+
public void Configure_AppliesShorterConsumptionTimeoutDefault_ForExpectedSkus(string sku, bool isLinux)
11284
{
113-
var settings = new Dictionary<string, string>();
114-
11585
var environment = new TestEnvironment();
116-
if (isLinuxConsumption)
86+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, sku);
87+
if (isLinux)
11788
{
11889
environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerName, "RandomContainerName");
11990
}
120-
121-
if (isWindowsConsumption)
122-
{
123-
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, ScriptConstants.DynamicSku);
124-
}
125-
91+
var settings = new Dictionary<string, string>();
12692
var options = GetConfiguredOptions(settings, environment);
12793

128-
Assert.Equal(ScriptJobHostOptionsSetup.DefaultFunctionTimeoutDynamic, options.FunctionTimeout);
129-
130-
// When functionTimeout is set as null
131-
settings.Add(ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout"), string.Empty);
94+
Assert.True(environment.IsConsumptionSku());
95+
Assert.Equal(ScriptJobHostOptionsSetup.DefaultConsumptionFunctionTimeout, options.FunctionTimeout);
96+
}
13297

133-
options = GetConfiguredOptions(settings, environment);
134-
Assert.Equal(ScriptJobHostOptionsSetup.DefaultFunctionTimeoutDynamic, options.FunctionTimeout);
98+
[Theory]
99+
[InlineData("")]
100+
[InlineData(ScriptConstants.FlexConsumptionSku)]
101+
[InlineData(ScriptConstants.ElasticPremiumSku)]
102+
public void Configure_AppliesLongerDedicatedTimeoutDefault_ForExpectedSkus(string sku)
103+
{
104+
var environment = new TestEnvironment();
105+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, sku);
135106

136-
// TODO: DI Need to ensure JobHostOptions is correctly configured
137-
//var timeoutConfig = options.HostOptions.FunctionTimeout;
138-
//Assert.NotNull(timeoutConfig);
139-
//Assert.True(timeoutConfig.ThrowOnTimeout);
140-
//Assert.Equal(scriptConfig.FunctionTimeout.Value, timeoutConfig.Timeout);
107+
var options = GetConfiguredOptions(new Dictionary<string, string>());
108+
Assert.Equal(ScriptJobHostOptionsSetup.DefaultFunctionTimeout, options.FunctionTimeout);
141109
}
142110

143111
[Fact]
144-
public void Configure_AppliesTimeout()
112+
public void Configure_AppliesConfiguredTimeout()
145113
{
146114
var settings = new Dictionary<string, string>
147115
{
@@ -230,50 +198,44 @@ public void Configure_AppliesRetry_ExponentialBackOffDelay(string expectedStrate
230198
Assert.Equal(maxIntervalTimeSpan, options.Retry.MaximumInterval);
231199
}
232200

233-
[Fact]
234-
public void Configure_TimeoutDefaultsNull_IfNotDynamic()
235-
{
236-
var options = GetConfiguredOptions(new Dictionary<string, string>());
237-
Assert.Equal(ScriptJobHostOptionsSetup.DefaultFunctionTimeout, options.FunctionTimeout);
238-
239-
// When functionTimeout is set as null
240-
var settings = new Dictionary<string, string>
241-
{
242-
{ ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout"), string.Empty }
243-
};
244-
245-
options = GetConfiguredOptions(settings);
246-
Assert.Equal(ScriptJobHostOptionsSetup.DefaultFunctionTimeout, options.FunctionTimeout);
247-
}
248-
249-
[Fact]
250-
public void Configure_NoMaxTimeoutLimits_IfNotDynamic()
201+
[Theory]
202+
[InlineData(ScriptConstants.ElasticPremiumSku)]
203+
[InlineData(ScriptConstants.FlexConsumptionSku)]
204+
[InlineData("")]
205+
public void Configure_NoMaxTimeoutLimits_ForSomeSkus(string sku)
251206
{
252207
var timeout = ScriptJobHostOptionsSetup.MaxFunctionTimeoutDynamic + TimeSpan.FromMinutes(10);
253208
string configPath = ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout");
254209
var settings = new Dictionary<string, string>
255210
{
256211
{ configPath, timeout.ToString() }
257212
};
213+
var environment = new TestEnvironment();
214+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, sku);
258215

259-
var options = GetConfiguredOptions(settings);
216+
var options = GetConfiguredOptions(settings, environment);
260217
Assert.Equal(timeout, options.FunctionTimeout);
261218
}
262219

263-
[Fact]
264-
public void Configure_AppliesInfiniteTimeout_IfNotDynamic()
220+
[Theory]
221+
[InlineData(ScriptConstants.ElasticPremiumSku)]
222+
[InlineData(ScriptConstants.FlexConsumptionSku)]
223+
[InlineData("")]
224+
public void Configure_AppliesInfiniteTimeout_ForSomeSkus(string sku)
265225
{
266226
var settings = new Dictionary<string, string>
267227
{
268228
{ ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout"), "-1" }
269229
};
230+
var environment = new TestEnvironment();
231+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, sku);
270232

271-
var options = GetConfiguredOptions(settings);
233+
var options = GetConfiguredOptions(settings, environment);
272234
Assert.Equal(null, options.FunctionTimeout);
273235
}
274236

275237
[Fact]
276-
public void Configure_AppliesTimeoutLimits_IfDynamic()
238+
public void Configure_AppliesExpectedTimeoutLimits_ForDynamicSku()
277239
{
278240
string configPath = ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout");
279241
var settings = new Dictionary<string, string>
@@ -282,7 +244,7 @@ public void Configure_AppliesTimeoutLimits_IfDynamic()
282244
};
283245

284246
var environment = new TestEnvironment();
285-
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, "Dynamic");
247+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSku, ScriptConstants.DynamicSku);
286248

287249
var ex = Assert.Throws<ArgumentException>(() => GetConfiguredOptions(settings, environment));
288250
var expectedMessage = "FunctionTimeout must be greater than 00:00:01 and less than 00:10:00.";
@@ -298,7 +260,7 @@ public void Configure_AppliesTimeoutLimits_IfDynamic()
298260
}
299261

300262
[Fact]
301-
public void Configure_MinTimeoutLimit_IfNotDynamic()
263+
public void Configure_AppliesMinTimeoutLimit_ForAllSkus()
302264
{
303265
string configPath = ConfigurationPath.Combine(ConfigurationSectionNames.JobHost, "functionTimeout");
304266
var settings = new Dictionary<string, string>

0 commit comments

Comments
 (0)