Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixing race condition with FunctionAssemblyLoadContext (#6632)
- Loading branch information
Showing
17 changed files
with
347 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
test/CSharpPrecompiledTestProjects/AssemblyLoadContextRace/AssemblyLoadContextRace.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
<AzureFunctionsVersion>v3</AzureFunctionsVersion> | ||
<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Net.Sdk.Functions" Version="3.0.*" /> | ||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Update="host.json"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</None> | ||
<None Update="local.settings.json"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
<CopyToPublishDirectory>Never</CopyToPublishDirectory> | ||
</None> | ||
</ItemGroup> | ||
</Project> |
55 changes: 55 additions & 0 deletions
55
test/CSharpPrecompiledTestProjects/AssemblyLoadContextRace/Function1.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using System.Runtime.Loader; | ||
using System.Threading; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Azure.WebJobs; | ||
using Microsoft.Azure.WebJobs.Extensions.Http; | ||
|
||
namespace AssemblyLoadContextRace | ||
{ | ||
public static class Function1 | ||
{ | ||
[FunctionName("Function1")] | ||
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req) | ||
{ | ||
var resetEvent = new ManualResetEvent(false); | ||
|
||
// First, force Newtonsoft to load on many threads, which induces the race | ||
var context = AssemblyLoadContext.GetLoadContext(typeof(Function1).Assembly); | ||
|
||
void LoadType() | ||
{ | ||
var assembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0")); | ||
} | ||
|
||
List<Thread> threads = new List<Thread>(); | ||
|
||
for (int i = 0; i < 100; i++) | ||
{ | ||
Thread t = new Thread(LoadType); | ||
threads.Add(t); | ||
t.Start(); | ||
} | ||
|
||
foreach (Thread t in threads) | ||
{ | ||
t.Join(); | ||
} | ||
|
||
// Now, make sure the assemblies match, signifying that the race was fixed and we | ||
// always load the host's version. | ||
var functionAssembly = context.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0")); | ||
var defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json, Version=12.0.3.0")); | ||
|
||
if (!Equals(functionAssembly, defaultAssembly)) | ||
{ | ||
throw new InvalidOperationException(); | ||
} | ||
|
||
return new OkResult(); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
test/CSharpPrecompiledTestProjects/AssemblyLoadContextRace/host.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"version": "2.0", | ||
"logging": { | ||
"applicationInsights": { | ||
"samplingExcludedTypes": "Request", | ||
"samplingSettings": { | ||
"isEnabled": true | ||
} | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
test/CSharpPrecompiledTestProjects/CSharpPrecompiledTestProjects.sln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.30413.136 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobsStartupTests", "WebJobsStartupTests\WebJobsStartupTests.csproj", "{EB7FC98C-1EF9-40E3-B7B2-858AA2547B1F}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyLoadContextRace", "AssemblyLoadContextRace\AssemblyLoadContextRace.csproj", "{1E882F3E-E1D1-4D56-A575-8530596705C3}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{EB7FC98C-1EF9-40E3-B7B2-858AA2547B1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{EB7FC98C-1EF9-40E3-B7B2-858AA2547B1F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{EB7FC98C-1EF9-40E3-B7B2-858AA2547B1F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{EB7FC98C-1EF9-40E3-B7B2-858AA2547B1F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{1E882F3E-E1D1-4D56-A575-8530596705C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{1E882F3E-E1D1-4D56-A575-8530596705C3}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{1E882F3E-E1D1-4D56-A575-8530596705C3}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{1E882F3E-E1D1-4D56-A575-8530596705C3}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {61422CE7-BD7A-46C1-9589-6ED6EE3AB8BC} | ||
EndGlobalSection | ||
EndGlobal |
File renamed without changes.
File renamed without changes.
19 changes: 19 additions & 0 deletions
19
test/CSharpPrecompiledTestProjects/WebJobsStartupTests/WebJobsStartupTests.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
<AzureFunctionsVersion>V3</AzureFunctionsVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.*" /> | ||
<PackageReference Include="Microsoft.Net.Sdk.Functions" Version="3.0.*" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Update="host.json"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</None> | ||
</ItemGroup> | ||
|
||
</Project> |
File renamed without changes.
32 changes: 32 additions & 0 deletions
32
test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/CSharpPrecompiledTestFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Microsoft.Azure.WebJobs.Script.Tests.Integration.WebHostEndToEnd | ||
{ | ||
public class CSharpPrecompiledEndToEndTestFixture : EndToEndTestFixture | ||
{ | ||
private const string TestPathTemplate = "..\\..\\..\\..\\CSharpPrecompiledTestProjects\\{0}\\bin\\Debug\\netcoreapp3.1"; | ||
private readonly IDisposable _dispose; | ||
|
||
public CSharpPrecompiledEndToEndTestFixture(string testProjectName, IDictionary<string, string> envVars = null) | ||
: base(string.Format(TestPathTemplate, testProjectName), testProjectName, "dotnet") | ||
{ | ||
if (envVars != null) | ||
{ | ||
_dispose = new TestScopedEnvironmentVariable(envVars); | ||
} | ||
} | ||
|
||
protected override Task CreateTestStorageEntities() | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
public override Task DisposeAsync() | ||
{ | ||
_dispose?.Dispose(); | ||
return base.DisposeAsync(); | ||
} | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...Jobs.Script.Tests.Integration/WebHostEndToEnd/FunctionAssemblyLoadContextEndToEndTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Net; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
namespace Microsoft.Azure.WebJobs.Script.Tests.Integration.WebHostEndToEnd | ||
{ | ||
public class FunctionAssemblyLoadContextEndToEndTests : IDisposable | ||
{ | ||
HostProcessLauncher _launcher; | ||
|
||
[Fact] | ||
public async Task Fallback_IsThreadSafe() | ||
{ | ||
_launcher = new HostProcessLauncher("AssemblyLoadContextRace"); | ||
await _launcher.StartHostAsync(); | ||
|
||
var client = _launcher.HttpClient; | ||
var response = await client.GetAsync($"api/Function1"); | ||
|
||
// The function does all the validation internally. | ||
Assert.Equal(HttpStatusCode.OK, response.StatusCode); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_launcher?.Dispose(); | ||
} | ||
} | ||
} |
Oops, something went wrong.