Skip to content

Conversation

@robcao
Copy link
Contributor

@robcao robcao commented Jun 4, 2024

What was changed

Updates the code generated rpc calls to just return the Task<Resp> instead of awaiting.

Why?

The current code is being awaited without a ConfigureAwait(false), which can cause deadlocks when being invoked inside synchronization contexts such as WindowsFormsSynchronizationContext.

Checklist

  1. Closes
    No issue created, discussed with Chad on Slack, could create an issue if desired.

  2. How was this tested:

I ran the existing tests locally and made sure they passed.

I could add a windows-only test for this if wanted, but this is very edge case and there are a few msbuild property changes needed to get WinForms into .net6 that would have to be windows-only.

Or I guess I could write a custom SynchronizationContext that does essentially the same thing, and use it for a test?

The deadlock can be simulated by running this console application on a Windows machine:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFormsRepro
{
	public class Program
	{
		public static async Task Main(string[] args)
		{
			SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

			Console.Out.WriteLine("About to call the workflow service!");

			await SimulateWorkflowServiceRpcAsync().ConfigureAwait(false);

			Console.Out.WriteLine("Finished calling the workflow service.");
		}


		public static async Task SimulateWorkflowServiceRpcAsync() => await SimulateTemporalRpcCallAsync();

		public static async Task SimulateTemporalRpcCallAsync()
		{
			var completion = new TaskCompletionSource<string>();

			Task task = Task.Run(() =>
			{
				Thread.Sleep(100);
				completion.SetResult("complete");
			});

			await task.ConfigureAwait(false);

		}
	}

}

with the following .csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

</Project>

I tested that changing SimulateWorkflowServiceRpcAsync to the following does not deadlock.

public static Task SimulateWorkflowServiceRpcAsync() => SimulateTemporalRpcCallAsync();
  1. Any docs updates needed?

No

Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, will merge if/when CI passes (I am merging main into your branch first).

@cretz cretz merged commit 43d0f86 into temporalio:main Jun 4, 2024
@robcao robcao deleted the async-rpc branch June 20, 2024 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants