Skip to content

Commit 6038158

Browse files
committed
Ensuring warmup file operations only happen if configuration is for standby state
1 parent 645e39b commit 6038158

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

src/WebJobs.Script.WebHost/Configuration/ScriptApplicationHostOptionsSetup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public void Configure(string name, ScriptApplicationHostOptions options)
5959
options.ScriptPath = Path.Combine(tempRoot, @"functions\standby\wwwroot");
6060
options.SecretsPath = Path.Combine(tempRoot, @"functions\standby\secrets");
6161
options.IsSelfHost = options.IsSelfHost;
62+
options.IsStandbyConfiguration = true;
6263
}
6364
}
6465

src/WebJobs.Script.WebHost/Standby/StandbyInitializationService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public StandbyInitializationService(IStandbyManager standbyManager)
1717
_standbyManager = standbyManager ?? throw new ArgumentNullException(nameof(standbyManager));
1818
}
1919

20-
public async Task StartAsync(CancellationToken cancellationToken)
20+
public Task StartAsync(CancellationToken cancellationToken)
2121
{
22-
await _standbyManager.InitializeAsync();
22+
return _standbyManager.InitializeAsync();
2323
}
2424

2525
public Task StopAsync(CancellationToken cancellationToken)

src/WebJobs.Script.WebHost/Standby/StandbyManager.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reactive.Linq;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Google.Protobuf.WellKnownTypes;
910
using Microsoft.AspNetCore.Hosting;
1011
using Microsoft.Azure.WebJobs.Script.Description;
1112
using Microsoft.Azure.WebJobs.Script.Diagnostics;
@@ -182,7 +183,17 @@ public async Task InitializeAsync()
182183

183184
private async Task CreateStandbyWarmupFunctions()
184185
{
185-
string scriptPath = _options.CurrentValue.ScriptPath;
186+
ScriptApplicationHostOptions options = _options.CurrentValue;
187+
188+
if (!options.IsStandbyConfiguration)
189+
{
190+
_logger.LogDebug(new EventId(600, "StandByWarmupFunctionsCreationOnSpecializedSite"),
191+
$"{nameof(CreateStandbyWarmupFunctions)} called with a specialized site configuration. Skipping warmup function creation.");
192+
193+
return;
194+
}
195+
196+
string scriptPath = options.ScriptPath;
186197
_logger.LogInformation($"Creating StandbyMode placeholder function directory ({scriptPath})");
187198

188199
await FileUtility.DeleteDirectoryAsync(scriptPath, true);

src/WebJobs.Script/Config/ScriptApplicationHostOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,7 @@ public class ScriptApplicationHostOptions
2929
public bool HasParentScope { get; set; }
3030

3131
public IServiceProvider RootServiceProvider { get; set; }
32+
33+
public bool IsStandbyConfiguration { get; internal set; }
3234
}
3335
}

test/WebJobs.Script.Tests.Integration/Host/StandbyManager/StandbyManagerE2ETestBase.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public StandbyManagerE2ETestBase()
4343
StandbyManager.ResetChangeToken();
4444
}
4545

46-
protected async Task InitializeTestHostAsync(string testDirName, IEnvironment environment)
46+
protected async Task<IWebHostBuilder> CreateWebHostBuilderAsync(string testDirName, IEnvironment environment)
4747
{
4848
var httpConfig = new HttpConfiguration();
4949
var uniqueTestRootPath = Path.Combine(_testRootPath, testDirName, Guid.NewGuid().ToString());
@@ -80,6 +80,7 @@ protected async Task InitializeTestHostAsync(string testDirName, IEnvironment en
8080
.ConfigureLogging(c =>
8181
{
8282
c.AddProvider(_loggerProvider);
83+
c.AddFilter((cat, lev) => true);
8384
})
8485
.ConfigureServices(c =>
8586
{
@@ -99,6 +100,12 @@ protected async Task InitializeTestHostAsync(string testDirName, IEnvironment en
99100
b.AddProvider(_loggerProvider);
100101
});
101102

103+
return webHostBuilder;
104+
}
105+
106+
protected async Task InitializeTestHostAsync(string testDirName, IEnvironment environment)
107+
{
108+
var webHostBuilder = await CreateWebHostBuilderAsync(testDirName, environment);
102109
_httpServer = new TestServer(webHostBuilder);
103110
_httpClient = _httpServer.CreateClient();
104111
_httpClient.BaseAddress = new Uri("https://localhost/");
@@ -165,9 +172,9 @@ protected static object GetCachedTimeZoneInfo()
165172

166173
public virtual void Dispose()
167174
{
168-
_loggerProvider.Dispose();
169-
_httpServer.Dispose();
170-
_httpClient.Dispose();
175+
_loggerProvider?.Dispose();
176+
_httpServer?.Dispose();
177+
_httpClient?.Dispose();
171178
CleanupTestDirectory();
172179
}
173180
}

test/WebJobs.Script.Tests.Integration/Host/StandbyManager/StandbyManagerE2ETests_Windows.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
using System.Collections.Generic;
99
using System.Diagnostics;
1010
using System.Linq;
11+
using System.Threading;
1112
using System.Threading.Tasks;
13+
using Microsoft.AspNetCore.Hosting;
14+
using Microsoft.Azure.WebJobs.Script.WebHost;
1215
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
16+
using Microsoft.Extensions.DependencyInjection;
1317
using Microsoft.WebJobs.Script.Tests;
1418
using Xunit;
1519

@@ -82,6 +86,51 @@ await TestHelpers.Await(() =>
8286
Assert.NotSame(GetCachedTimeZoneInfo(), _originalTimeZoneInfoCache);
8387
}
8488

89+
[Fact]
90+
public async Task InitialisAsync_WithSpecializedSite_SkipsWarmupFunctionsAndLogs()
91+
{
92+
_settings.Add(EnvironmentSettingNames.AzureWebsiteInstanceId, Guid.NewGuid().ToString());
93+
var environment = new TestEnvironment(_settings);
94+
95+
// We cannot create and run a full test host as there's no way to issue
96+
// requests to the TestServer before initialization has occurred.
97+
var webHostBuilder = await CreateWebHostBuilderAsync("Windows", environment);
98+
IWebHost host = webHostBuilder.Build();
99+
100+
// Pull the service out of the built host. If it were easier to construct, we'd do that instead.
101+
var standbyManager = host.Services.GetService<IStandbyManager>();
102+
var scriptHostManager = host.Services.GetService<IScriptHostManager>() as WebJobsScriptHostService;
103+
104+
// Simulate the race condition by flipping the specialization env vars and calling
105+
// Specialize before the call to Initialize was made.
106+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0");
107+
environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteContainerReady, "1");
108+
109+
bool changeTokenFired = false;
110+
using (StandbyManager.ChangeToken.RegisterChangeCallback(_ => changeTokenFired = true, null))
111+
{
112+
Task specializeTask = standbyManager.SpecializeHostAsync();
113+
114+
await TestHelpers.Await(() => changeTokenFired);
115+
116+
await standbyManager.InitializeAsync();
117+
118+
await TestHelpers.Await(() => _loggerProvider.GetLog().Contains(" called with a specialized site configuration. Skipping warmup function creation."));
119+
120+
// Note: we also need to start the ScriptHostManager or else specialization will never complete
121+
await scriptHostManager.StartAsync(CancellationToken.None);
122+
123+
await specializeTask;
124+
125+
Assert.True(changeTokenFired);
126+
127+
bool warmupCreationLogPresent = _loggerProvider.GetAllLogMessages()
128+
.Any(p => p.FormattedMessage != null && p.FormattedMessage.StartsWith("Creating StandbyMode placeholder function directory"));
129+
130+
Assert.False(warmupCreationLogPresent);
131+
}
132+
}
133+
85134
[Fact(Skip = "https://github.com/Azure/azure-functions-host/issues/4230")]
86135
public async Task StandbyModeE2E_Java()
87136
{

0 commit comments

Comments
 (0)