Await outstanding async work in .NET. (#6993)
The Pulumi .NET SDK does not currently await all outstanding asynchronous work associated with a Pulumi program. Because all relevant asynchronous work is created via the Pulumi SDK, we can track this asynchronous work and ensure that it has all completed prior to returning from `Deployment.RunAsync`. The implementation here is simpler than that in #6983, and re-uses the existing support for tracking outstanding RPCs. If this proves to negatively impact performance (which is a very real possibility for programs that create many `Output` instances), we can simplify this using a semaphore and a counter (essentially Go's `sync.WaitGroup`). This fixes the .NET portion of #3991.
This commit is contained in:
parent
be8183180d
commit
bd18384038
|
@ -12,17 +12,21 @@
|
|||
|
||||
### Bug Fixes
|
||||
|
||||
- [auto/dotnet] - Disable Language Server Host logging and checking appsettings.json config
|
||||
[#7023](https://github.com/pulumi/pulumi/pull/7023)
|
||||
- [auto/dotnet] - Disable Language Server Host logging and checking appsettings.json config
|
||||
[#7023](https://github.com/pulumi/pulumi/pull/7023)
|
||||
|
||||
- [auto/python] - Export missing `ProjectBackend` type
|
||||
[#6984](https://github.com/pulumi/pulumi/pull/6984)
|
||||
- [auto/python] - Export missing `ProjectBackend` type
|
||||
[#6984](https://github.com/pulumi/pulumi/pull/6984)
|
||||
|
||||
- [sdk/nodejs] - Fix noisy errors.
|
||||
[#6995](https://github.com/pulumi/pulumi/pull/6995)
|
||||
- [sdk/nodejs] - Fix noisy errors.
|
||||
[#6995](https://github.com/pulumi/pulumi/pull/6995)
|
||||
|
||||
- Config: Avoid emitting integers in objects using exponential notation.
|
||||
[#7005](https://github.com/pulumi/pulumi/pull/7005)
|
||||
- Config: Avoid emitting integers in objects using exponential notation.
|
||||
[#7005](https://github.com/pulumi/pulumi/pull/7005)
|
||||
|
||||
- [codegen/python] - Fix issue with lazy_import affecting pulumi-eks
|
||||
[#7024](https://github.com/pulumi/pulumi/pull/7024)
|
||||
- [codegen/python] - Fix issue with lazy_import affecting pulumi-eks
|
||||
[#7024](https://github.com/pulumi/pulumi/pull/7024)
|
||||
|
||||
- Ensure that all outstanding asynchronous work is awaited before returning from a .NET
|
||||
Pulumi program.
|
||||
[#6993](https://github.com/pulumi/pulumi/pull/6993)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2016-2021, Pulumi Corporation
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Pulumi.Testing;
|
||||
using Pulumi.Tests.Mocks;
|
||||
|
@ -85,5 +86,24 @@ namespace Pulumi.Tests
|
|||
tcs.SetResult(1);
|
||||
await runTaskOne;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunWaitsForOrphanedOutput()
|
||||
{
|
||||
var result = 0;
|
||||
var tcs = new TaskCompletionSource<int>();
|
||||
var runTaskOne = Deployment.CreateRunnerAndRunAsync(
|
||||
() => new Deployment(new MockEngine(), new MockMonitor(new MyMocks()), null),
|
||||
runner => runner.RunAsync(() =>
|
||||
{
|
||||
Output.Create(tcs.Task).Apply(i => result = i);
|
||||
return Task.FromResult((IDictionary<string, object?>)new Dictionary<string, object?>());
|
||||
}, null));
|
||||
|
||||
tcs.SetResult(42);
|
||||
await runTaskOne;
|
||||
|
||||
Assert.Equal(42, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,12 @@ namespace Pulumi.Tests
|
|||
|
||||
private static async Task Run(Func<Task> func, bool dryRun)
|
||||
{
|
||||
var mock = new Mock<IDeployment>(MockBehavior.Strict);
|
||||
var runner = new Mock<IRunner>(MockBehavior.Strict);
|
||||
runner.Setup(r => r.RegisterTask(It.IsAny<string>(), It.IsAny<Task>()));
|
||||
|
||||
var mock = new Mock<IDeploymentInternal>(MockBehavior.Strict);
|
||||
mock.Setup(d => d.IsDryRun).Returns(dryRun);
|
||||
mock.Setup(d => d.Runner).Returns(runner.Object);
|
||||
|
||||
Deployment.Instance = new DeploymentInstance(mock.Object);
|
||||
await func().ConfigureAwait(false);
|
||||
|
|
|
@ -89,9 +89,13 @@ namespace Pulumi.Tests
|
|||
// Arrange
|
||||
Output<IDictionary<string, object?>>? outputs = null;
|
||||
|
||||
var runner = new Mock<IRunner>(MockBehavior.Strict);
|
||||
runner.Setup(r => r.RegisterTask(It.IsAny<string>(), It.IsAny<Task>()));
|
||||
|
||||
var mock = new Mock<IDeploymentInternal>(MockBehavior.Strict);
|
||||
mock.Setup(d => d.ProjectName).Returns("TestProject");
|
||||
mock.Setup(d => d.StackName).Returns("TestStack");
|
||||
mock.Setup(d => d.Runner).Returns(runner.Object);
|
||||
mock.SetupSet(content => content.Stack = It.IsAny<Stack>());
|
||||
mock.Setup(d => d.ReadOrRegisterResource(It.IsAny<Stack>(), It.IsAny<bool>(),
|
||||
It.IsAny<Func<string, Resource>>(), It.IsAny<ResourceArgs>(), It.IsAny<ResourceOptions>()));
|
||||
|
|
|
@ -138,8 +138,14 @@ namespace Pulumi
|
|||
{
|
||||
internal Task<OutputData<T>> DataTask { get; private set; }
|
||||
|
||||
internal Output(Task<OutputData<T>> dataTask)
|
||||
=> DataTask = dataTask;
|
||||
internal Output(Task<OutputData<T>> dataTask) {
|
||||
this.DataTask = dataTask;
|
||||
|
||||
if (Deployment.TryGetInternalInstance(out var instance))
|
||||
{
|
||||
instance.Runner.RegisterTask("Output<>", dataTask);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<T> GetValueAsync()
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Pulumi.Testing;
|
||||
|
@ -57,6 +58,18 @@ namespace Pulumi
|
|||
}
|
||||
}
|
||||
|
||||
internal static bool TryGetInternalInstance([NotNullWhen(true)] out IDeploymentInternal? instance)
|
||||
{
|
||||
if (_instance.Value != null)
|
||||
{
|
||||
instance = _instance.Value.Internal;
|
||||
return true;
|
||||
}
|
||||
|
||||
instance = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IDeploymentInternal InternalInstance
|
||||
=> Instance.Internal;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Immutable;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using Pulumi.Testing;
|
||||
|
||||
namespace Pulumi
|
||||
|
@ -188,7 +189,11 @@ namespace Pulumi
|
|||
Func<Deployment> deploymentFactory,
|
||||
Func<IRunner, Task<int>> runAsync)
|
||||
{
|
||||
// Serilog.Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console().CreateLogger();
|
||||
var enableVerboseLogging = Environment.GetEnvironmentVariable("PULUMI_DOTNET_LOG_VERBOSE");
|
||||
if (enableVerboseLogging != null && enableVerboseLogging != "")
|
||||
{
|
||||
Serilog.Log.Logger = new Serilog.LoggerConfiguration().MinimumLevel.Debug().WriteTo.Console().CreateLogger();
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("Deployment.Run called.");
|
||||
Serilog.Log.Debug("Creating new Deployment.");
|
||||
|
|
Loading…
Reference in a new issue