2

I have a Unity game, implementing a gRPC client that is generated from the protobuf compiler. While the game is running, I can receive all the data I need from the streaming call, and interact with that data perfectly. The issue I have is in the shutdown of the game and cleanup of the gRPC client/channel (I believe).

When I attempt to exit play mode, it retains a connection to the server, and the Unity editor hangs (presumably waiting for the PlotManager.OnDisable code ShutdownAsync.Wait() call).

The only way to remedy this at the moment is to shutdown my server process, which causes the connection to be lost, and Unity editor returns to normal functionality.

How can I best manage the lifecycle of the Client / Channel to ensure the Unity game cleans up correctly?

public class PlotRenderer : MonoBehaviour
{
    private bool _subscribed = false;
    private CancellationTokenSource _cancellationToken;

    public async void Subscribe()
    {
        this._subscribed = true;
        this._cancellationToken = new CancellationTokenSource();
        
        using (var call = PlotManager.s.Client.SubscribePlotCellUpdates(
                   new PrimaryKey { Id = this._plot.Id },
                   cancellationToken: this._cancellationToken.Token))
        {
            var responseReader = Task.Run(async () =>
            {
                while (this._subscribed
                && await call.ResponseStream.MoveNext(this._cancellationToken.Token))
                {
                    var cell = call.ResponseStream.Current;

                    // Add cell to a list.
                }
                this.Unsubscribe();
            });
            await responseReader;
        }
    }

    public void Unsubscribe()
    {
        if (this._cancellationToken != null)
            this._cancellationToken.Cancel();
        this._subscribed = false;
    }

    // Called when the object is being destroyed (game stopping)
    private void OnDestroy()
    {
        this.Unsubscribe();
    }
}

Relevant code from my PlotManager class is:

public class PlotManager
{
    public static PlotManager s;
    public Plotty.PlottyClient Client;
    public Channel Channel;
    public string Address = "127.0.0.1:8075"

    // Called when object is created and enabled in game
    private void OnEnable()
    {
        this.Channel = new Channel(this.Address, ChannelCredentials.Insecure);
        return new Plotty.PlottyClient(this.Channel);
    }

    // Called when the object is being destroyed (game stopping)
    private void OnDisable()
    {
        this.Channel.ShutdownAsync().Wait();
        this.Channel = null;
        this.Client = null;
    } 
}
Predominant
  • 1,460
  • 12
  • 24
  • 1
    I got the same problem, documentation is really bad on this topic. Did you find out anything new? – JustRandom May 11 '22 at 17:39
  • I could fix my problem by making sure Dispose() on all channels is being called before calling ShutdownAsync().Wait(); Your loop gets stuck at await call.ResponseStream.MoveNext(this._cancellationToken.Token) and Dispose() via the "using" keyword is never called. That is why you get stuck. Make sure that your while loop ends before ShutdownAsync().Wait() is called. @Predominant – JustRandom May 15 '22 at 15:06

0 Answers0