Send message just before disconnect, make sure arrives

With closing of my application want to publish some message.
I already use atLeastIonce, now to make sure the message arrives i now have the following construction, i wish for a solution where i can do without application.processmessages.

(if i do the disconnect right after the SendApplicationClosedMessage, the message does not arrive at the broker)

Any idea/suggestion ?

  if FListening then
  begin
    FNotifyLastSeenTimer.Enabled := False;
    nu := Now;
   SendApplicationClosedMessage();
    while MQTTInstance.Session.LastReadCommunicationTime<nu do
    begin
      sleep(50);
      Application.ProcessMessages;
    end;
    MQTTInstance.Disconnect;
    FListening := False;
  end;

Internally, the MQTT client is thread based. If you send a command, the thread will process this and send it, but if you do a disconnect immediately after send, the thread's execution is immediately stopped and it is likely the message to be sent is not longer processed by the internal thread.
If we change the disconnect behavior to not let it be executed immediately, that might have undesirable effects in other use cases.

I understand.

Would it be an idea, to introduce a Flush method ?
Maybe in combination with the disconnect ?

procedure Disconnect(const AEmptyQueue : Boolean);

Now there is no descent way to make sure, al messages are send.

I make sometimes 2 methods to stop threadbased queue classes,

procedure Stop(); // Stops & processes the queueu until empty
procedure Cancel(); // Stops & forgets about the queue.

(just an example, not that i have to explain that to you guys :) )

Hello!

We also want to send a message just before disconnect.

The idea of @Ben_Simons to introduce a parameter to the Disconnect method seems like a perfect idea and would not change existing applications.
Are there any improvements planned @brunofierens ?

1 Like

Our focus in the past months was on adding MQTT v5 compatibility.
We will investigate further extensions.

1 Like

Hello, are there any news about this topic?

There are a couple of options:

A "last will" message with a TTMSMQTTClient.LastWillSettings.QoS := qosExactlyOnce can be used.

If you prefer to send a custom message then I would suggest using TForm.OnCloseQuery to hide the application while it sends a custom message with QoS := qosExactlyOnce and save the packet identifier.

Then wait until a PUBCOMP is received with the same packet identifier before disconnecting and closing the application.

If you just want to make sure all queued packets were sent then I would suggest using TForm.OnCloseQuery to hide the application and check TTMSMQTTClient.Session.HasOutgoingPackets before disconnecting and closing the application.

Hi!

Thank you, this works:

procedure TForm1.DisconnectMqtt();
begin
  mqttClient.Publish('test/is_online', 'False', qosExactlyOnce, True);
  while mqttClient.Session.HasOutgoingPackets do begin
    Sleep(2);
  end;

  mqttClient.Disconnect;
end;

So why not introduce a parameter to the Disconnect function which does exactly that?

Thanks for the suggestion, we will investigate this.