Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managed MQTT client hangs when trying to disconnect using StopAsync() in Unity Engine #2006

Open
Joe-Heffer-Shef opened this issue May 22, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@Joe-Heffer-Shef
Copy link

I am using

Describe the bug

When I run ManagedMqttClient.StopAsync() the task hangs on this line:

await Task.WhenAny(_maintainConnectionTask);

Which component is your bug related to?

ManagedMqttClient

To Reproduce

var mqttFactory = new MqttFactory();
var client = mqttFactory.CreateManagedMqttClient();
var task = client.StartAsync(ClientOptions);
task.Wait();
var task = Client.StopAsync(cleanDisconnect: false);
task.Wait();
# Hangs

Expected behavior

I expect this to disconnect in under a second.

@Joe-Heffer-Shef Joe-Heffer-Shef added the bug Something isn't working label May 22, 2024
@Joe-Heffer-Shef Joe-Heffer-Shef changed the title Managed MQTT client hangs when trying to disconnect (StopAsync()) Managed MQTT client hangs when trying to disconnect using StopAsync() May 22, 2024
@chkr1011
Copy link
Collaborator

I created a Unit Test with your code and it runs fine.
Does this also occur with later versions?

@Joe-Heffer-Shef
Copy link
Author

Joe-Heffer-Shef commented May 23, 2024

I am using version 4.3.5 which I believe is the latest version which I installed from NuGet.

Thank you for running that test. I also ran the code above as a unit test and it does indeed work fine. I think the problem is happening when I run this same code inside Unity Editor for the Unity Game Engine. (I should've explained this context before, but I assumed the problem was with the MQTTnet library itself.)

It seems like there's something in StopAsync() or MaintainConnectionAsync() that works differently in the context of a Unity Engine environment.

Is there a way to set a disconnect timeout so that StopAsync() will throw an exception after x seconds?

The code examples for the two unit tests are below:

This works:

// NOT in Unity Engine
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;

namespace TestProject1;

public class Tests
{
    [SetUp]
    public void Setup()
    {
    }

    [Test]
    public void Test1()
    {
        // https://github.com/dotnet/MQTTnet/wiki/Client#client-options
        var options = new MqttClientOptionsBuilder()
            .WithTcpServer("broker.emqx.io", 1883)
            .Build();

        var managedOptions = new ManagedMqttClientOptionsBuilder()
            .WithClientOptions(options)
            .Build();

        var mqttFactory = new MqttFactory();
        var client = mqttFactory.CreateManagedMqttClient();
        var task = client.StartAsync(managedOptions);
        task.Wait();
        task = client.StopAsync(cleanDisconnect: false);
        task.Wait();

        Assert.Pass();
    }
}

This Unity code hangs:

// Unity Engine testing with NUnit
using NUnit.Framework;
using UnityEngine;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;


namespace MyProject.Core.Tests
{
    public class MqttNetTests
    {
        /// <summary>
        /// Test the mqttnet library on its own.
        /// </summary>
        [Test]
        public void MqttNetStopAsync()
        {
            // Set up MQTT client
            var options = new MqttClientOptionsBuilder()
                .WithTcpServer("broker.emqx.io", 1883)
                .Build();

            var managedOptions = new ManagedMqttClientOptionsBuilder()
                .WithClientOptions(options)
                .Build();

            var mqttFactory = new MqttFactory();
            var client = mqttFactory.CreateManagedMqttClient();

            // Connect
            var task = client.StartAsync(managedOptions);
            task.Wait();
            Debug.Log("MQTT client started.");

            // Disconnect
            task = client.StopAsync(cleanDisconnect: false);
            task.Wait(); // HANGS
            Debug.Log("MQTT client stopped.");

            Assert.Pass();
        }
    }
}

@Joe-Heffer-Shef Joe-Heffer-Shef changed the title Managed MQTT client hangs when trying to disconnect using StopAsync() Managed MQTT client hangs when trying to disconnect using StopAsync() in Unity Engine May 23, 2024
@chkr1011
Copy link
Collaborator

My recommendation is to avoid the managed client in this case. The regular client gives you more flexibility. But it requires manual reconnecting etc. Please let me know if the regular client has the same issues in Unity.

@Joe-Heffer-Shef
Copy link
Author

The unmanaged client works fine with Unity. Thanks for your help Christian @chkr1011

@xjekali
Copy link

xjekali commented Jun 19, 2024

I am seeing a similar hang when calling StopAsync from a SpecFlow test (no Unity involved, but I may be doing stuff to paint myself into a similar corner).

My problem can be alleviated if I add a .ConfigureAwait(false) to the Task.WhenAny call on line 286 here:

if (_maintainConnectionTask != null)
{
await Task.WhenAny(_maintainConnectionTask);
_maintainConnectionTask = null;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

3 participants