dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.47k stars 1.07k forks source link

PublishAsync fails with ObjectDisposedException on 'AsyncLockWaiter' #1791

Open stefanocadoaleph opened 1 year ago

stefanocadoaleph commented 1 year ago

Verification

Describe the bug

Running an application with an MQTT client connected to a VerneMQ broker running as a docker container on a different host. The client is publishing successfully at a rate of 92 msg/s. When the vernemq container is paused to simulate a communication failure, each PublishAsync operation times out due to the corresponding CancellationToken (created with the designated timeout time). client.DisconnectedAsync handler is never called also after waiting for KeepAlivePeriod to be elapsed.

After the vernemq container is resumed, some PublishAsync that may be still pending completed with the following exception:

MQTTTransportDataSource...Publish(messageid:bd169c58-e910-4c63-bdec-8e7743f2f9e0)..Communication error with the broker: Cannot access a disposed object.
      Object name: 'AsyncLockWaiter'.
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'AsyncLockWaiter'.
   at MQTTnet.Adapter.MqttChannelAdapter.SendPacketAsync(MqttPacket packet, CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.PublishAtMostOnce(MqttPublishPacket publishPacket, CancellationToken cancellationToken)

and then, finally DisconnectedAsync handler is triggered:

warn: Opc.Ua.PubSub.MQTTDataSource[0]
      Mqtt client disconnected: NormalDisconnection

Which component is your bug related to?

To Reproduce

Steps to reproduce the behavior:

  1. Using this version of MQTTnet '4.2.1.781'.
  2. See description of the bug.
  3. See error.

Expected behavior

I expect all the PublishAsync tasks to complete with exeption or to be cancelled and client.DisconnectedAsync to be invoked after MqttClientOptions.Timeout or given CancellationToken.

weichaohh commented 1 month ago

you can transfer timeout CancellationToken for PublishAsync。