diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc8f88781..ae93d03a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,11 +21,6 @@ jobs: - os: ubuntu-latest docsTarget: true cloudTestTarget: true - # This is here alongside docsTarget because newer docfx doesn't work - # with .NET 6. - dotNetVersionOverride: | - 6.x - 8.x - os: ubuntu-arm runsOn: ubuntu-24.04-arm64-2-core - os: macos-intel @@ -54,7 +49,7 @@ jobs: with: # Specific .NET version required because GitHub macos ARM image has # bad pre-installed .NET version - dotnet-version: ${{ matrix.dotNetVersionOverride || '6.x' }} + dotnet-version: '10.x' - name: Install protoc uses: arduino/setup-protoc@v3 diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 8e931a8a9..f709bb149 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -32,7 +32,7 @@ jobs: out-file: libtemporal_sdk_core_c_bridge.so out-prefix: linux-musl-x64 # Need Alpine container since GH runner doesn't have one - container: mcr.microsoft.com/dotnet/sdk:8.0-alpine + container: mcr.microsoft.com/dotnet/sdk:10.0-alpine protobuf-url: https://github.com/protocolbuffers/protobuf/releases/download/v22.3/protoc-22.3-linux-x86_64.zip runsOn: ubuntu-latest - os: macos-intel @@ -135,6 +135,8 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.x - name: Build package run: dotnet pack -c Release /p:BridgeLibraryRoot=${{ github.workspace }}/bridge-libraries @@ -164,7 +166,7 @@ jobs: - os: ubuntu-arm runsOn: ubuntu-24.04-arm64-2-core - os: alpine-latest - container: mcr.microsoft.com/dotnet/sdk:6.0-alpine + container: mcr.microsoft.com/dotnet/sdk:10.0-alpine runsOn: ubuntu-latest - os: macos-intel runsOn: macos-13 @@ -192,11 +194,7 @@ jobs: with: # Specific .NET version required because GitHub macos ARM image has # bad pre-installed .NET version - dotnet-version: 6.x - - - name: Setup .NET (Alpine) - if: ${{ matrix.os == 'alpine-latest' }} - run: apk add dotnet6-sdk + dotnet-version: 10.x - name: Run smoke test (non-Windows) if: ${{ matrix.os != 'windows-latest' && matrix.os != 'windows-arm' }} diff --git a/README.md b/README.md index d0a8d3250..e35d8bca2 100644 --- a/README.md +++ b/README.md @@ -803,6 +803,9 @@ dotnet_diagnostic.CA1024.severity = none # Don't force workflows to have static methods dotnet_diagnostic.CA1822.severity = none +# Don't force workflows to call async methods +dotnet_diagnostic.CA1849.severity = none + # Do not need ConfigureAwait for workflows dotnet_diagnostic.CA2007.severity = none @@ -815,6 +818,9 @@ dotnet_diagnostic.CA5394.severity = none # Allow async methods to not have await in them dotnet_diagnostic.CS1998.severity = none +# Don't force workflows to call async methods +dotnet_diagnostic.VSTHRD103.severity = none + # Don't avoid, but rather encourage things using TaskScheduler.Current in workflows dotnet_diagnostic.VSTHRD105.severity = none ``` diff --git a/src/Temporalio.Api.Generator/Temporal.Api.Generator.csproj b/src/Temporalio.Api.Generator/Temporal.Api.Generator.csproj index 1d01086d5..de64433c5 100644 --- a/src/Temporalio.Api.Generator/Temporal.Api.Generator.csproj +++ b/src/Temporalio.Api.Generator/Temporal.Api.Generator.csproj @@ -3,7 +3,7 @@ enable Exe - net6.0 + net10.0 diff --git a/tests/Temporalio.SimpleBench/Program.cs b/tests/Temporalio.SimpleBench/Program.cs index 2bdb96571..8ca5312c8 100644 --- a/tests/Temporalio.SimpleBench/Program.cs +++ b/tests/Temporalio.SimpleBench/Program.cs @@ -77,7 +77,7 @@ resultWatch.Stop(); // Cancel worker and wait for cancelled - cancelSource.Cancel(); + await cancelSource.CancelAsync(); try { await workerTask; diff --git a/tests/Temporalio.SimpleBench/Temporalio.SimpleBench.csproj b/tests/Temporalio.SimpleBench/Temporalio.SimpleBench.csproj index 4b69ca335..dbb19137a 100644 --- a/tests/Temporalio.SimpleBench/Temporalio.SimpleBench.csproj +++ b/tests/Temporalio.SimpleBench/Temporalio.SimpleBench.csproj @@ -3,14 +3,14 @@ enable Exe - net6.0 + net10.0 - - + + diff --git a/tests/Temporalio.SmokeTest/Temporalio.SmokeTest.csproj b/tests/Temporalio.SmokeTest/Temporalio.SmokeTest.csproj index 177da0670..55ca666ec 100644 --- a/tests/Temporalio.SmokeTest/Temporalio.SmokeTest.csproj +++ b/tests/Temporalio.SmokeTest/Temporalio.SmokeTest.csproj @@ -3,7 +3,7 @@ enable Exe - net6.0 + net10.0 - - - - diff --git a/tests/Temporalio.Tests/TestUtils.cs b/tests/Temporalio.Tests/TestUtils.cs index 84a370617..c48e4a231 100644 --- a/tests/Temporalio.Tests/TestUtils.cs +++ b/tests/Temporalio.Tests/TestUtils.cs @@ -19,7 +19,7 @@ public static string ReadAllFileText( public static int FreePort() { - var l = new TcpListener(IPAddress.Loopback, 0); + using var l = new TcpListener(IPAddress.Loopback, 0); l.Start(); int port = ((IPEndPoint)l.LocalEndpoint).Port; l.Stop(); diff --git a/tests/Temporalio.Tests/Testing/ActivityEnvironmentTests.cs b/tests/Temporalio.Tests/Testing/ActivityEnvironmentTests.cs index 1a18f8ee4..c74fa45ef 100644 --- a/tests/Temporalio.Tests/Testing/ActivityEnvironmentTests.cs +++ b/tests/Temporalio.Tests/Testing/ActivityEnvironmentTests.cs @@ -23,7 +23,7 @@ public async Task RunAsync_SimpleActivity_Succeeds() Info = ActivityEnvironment.DefaultInfo with { ActivityType = "SomeActivity" }, Heartbeater = heartbeats.Add, }; - env.WorkerShutdownTokenSource.Cancel(); + await env.WorkerShutdownTokenSource.CancelAsync(); env.Cancel(ActivityCancelReason.Timeout); var ret = await env.RunAsync(async () => { diff --git a/tests/Temporalio.Tests/Worker/ActivityWorkerTests.cs b/tests/Temporalio.Tests/Worker/ActivityWorkerTests.cs index fc3e67806..608128c77 100644 --- a/tests/Temporalio.Tests/Worker/ActivityWorkerTests.cs +++ b/tests/Temporalio.Tests/Worker/ActivityWorkerTests.cs @@ -433,7 +433,7 @@ await Assert.ThrowsAnyAsync(() => ExecuteActivityAsy workflowId = handle.Id; // Wait for activity to be reached, then stop the worker await activityReached.Task.WaitAsync(TimeSpan.FromSeconds(20)); - workerStoppingSource.Cancel(); + await workerStoppingSource.CancelAsync(); })); Assert.True(gotCancellation); // Check the workflow error diff --git a/tests/Temporalio.Tests/Worker/NexusWorkerTests.cs b/tests/Temporalio.Tests/Worker/NexusWorkerTests.cs index 273e3ee14..efd0f71a2 100644 --- a/tests/Temporalio.Tests/Worker/NexusWorkerTests.cs +++ b/tests/Temporalio.Tests/Worker/NexusWorkerTests.cs @@ -216,7 +216,12 @@ await AssertMore.HasEventEventuallyAsync( svc => svc.DoSomething("some-name"), new() { CancellationToken = cancelSource.Token }); // Cancel and wait for result to bubble out cancel +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 cancelSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method await handle.GetResultAsync(); })); var inner = Assert.IsType(wfExc.InnerException); diff --git a/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs b/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs index 2cc46ac72..f52dc53a4 100644 --- a/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs +++ b/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs @@ -284,16 +284,14 @@ public enum Scenario TaskWaitAsync, // https://github.com/dotnet/runtime/issues/83159 DataflowReceiveAsync, - // https://github.com/dotnet/runtime/issues/87481 - TaskWhenAnyWithResultThreeParam, ListenerDisabledCreateCommand, // Good TaskFactoryStartNew, TaskStart, TaskContinueWith, - // https://github.com/dotnet/runtime/issues/87481 TaskWhenAnyWithResultTwoParam, + TaskWhenAnyWithResultThreeParam, WorkflowWhenAnyWithResultThreeParam, WorkflowWhenAll, WorkflowRunTask, @@ -333,9 +331,6 @@ await AssertScenarioFailsTask( await AssertScenarioFailsTask( StandardLibraryCallsWorkflow.Scenario.DataflowReceiveAsync, "not scheduled on workflow scheduler"); - await AssertScenarioFailsTask( - StandardLibraryCallsWorkflow.Scenario.TaskWhenAnyWithResultThreeParam, - "not scheduled on workflow scheduler"); await AssertScenarioFailsTask( StandardLibraryCallsWorkflow.Scenario.ListenerDisabledCreateCommand, "Function during tracing event listener disabling created workflow commands"); @@ -360,6 +355,8 @@ Task AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario scenario) => await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.TaskStart); await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.TaskContinueWith); await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.TaskWhenAnyWithResultTwoParam); + // Starting in .NET 8, https://github.com/dotnet/runtime/issues/87481 is fixed + await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.TaskWhenAnyWithResultThreeParam); await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.WorkflowWhenAnyWithResultThreeParam); await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.WorkflowWhenAll); await AssertScenarioSucceeds(StandardLibraryCallsWorkflow.Scenario.WorkflowRunTask); @@ -551,7 +548,12 @@ public async Task RunAsync(Input input) using var cancelSource = new CancellationTokenSource(); if (input.CancelBefore) { +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 cancelSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method } else if (input.CancelAfterMS > 0) { @@ -1302,7 +1304,12 @@ public Task RunAsync(int timeoutMs) => public async Task ProceedAsync() => shouldProceed = true; [WorkflowSignal] +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 public async Task CancelWaitAsync() => cancelSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method } [Fact] @@ -2007,7 +2014,12 @@ public async Task RunAsync(Input input) // Cancel before if desired if (input.BeforeStart) { +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 tokenSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method } Task activity; if (input.Local) @@ -2036,7 +2048,12 @@ public async Task RunAsync(Input input) if (!input.BeforeStart) { await Workflow.DelayAsync(1); +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 tokenSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method } await activity; } @@ -2255,7 +2272,12 @@ public async Task RunAsync(bool beforeStart) // Cancel before if desired if (beforeStart) { +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 tokenSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async method } var handle = await Workflow.StartChildWorkflowAsync( (ChildWorkflow wf) => wf.RunAsync(), @@ -2263,7 +2285,12 @@ public async Task RunAsync(bool beforeStart) // If not cancel before, cancel now if (!beforeStart) { +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 tokenSource.Cancel(); +#pragma warning restore VSTHRD103 // Call async methods when in an async method +#pragma warning restore CA1849 // Call async methods when in an async methodßß } await handle.GetResultAsync(); } @@ -4088,7 +4115,7 @@ await ExecuteWorkerAsync(async worker => await AssertMore.EqualEventuallyAsync(true, () => handle.QueryAsync(wf => wf.Waiting)); // Cancel and confirm error - updateCancelSource.Cancel(); + await updateCancelSource.CancelAsync(); await Assert.ThrowsAsync(() => updateTask); }); } @@ -5297,7 +5324,12 @@ await Workflow.ExecuteActivityAsync( } [WorkflowSignal] +#pragma warning disable CA1849 // Call async methods when in an async method +#pragma warning disable VSTHRD103 // Call async methods when in an async method + // https://github.com/temporalio/sdk-dotnet/issues/327 public async Task CancelUpdateAsync(int number) => cancellations[number].Cancel(); +#pragma warning restore VSTHRD103 +#pragma warning restore CA1849 #pragma warning disable VSTHRD110 // Returning tasks is ok private Task WaitAsync(CancellationToken? cancellationToken = null) => @@ -6512,7 +6544,7 @@ await AssertMore.EventuallyAsync(async () => }); // Now cancel token and confirm update cancellation results in proper cancellation - cancelSource.Cancel(); + await cancelSource.CancelAsync(); await Assert.ThrowsAsync( () => updateTask); // Note, currently in this use case the handle isn't set either, the same exception