TsgcWebSocketClientEvents › OnQueueDrained

OnQueueDrained Event

Fires when the outbound message queue goes from holding messages to being empty.

Syntax

property OnQueueDrained: TsgcWSQueueDrainedEvent;
// TsgcWSQueueDrainedEvent = procedure(Connection: TsgcWSConnection) of object

Default Value

Remarks

Only fires when message queuing is active, that is when QueueOptions.Text.Level, QueueOptions.Binary.Level or QueueOptions.Ping.Level is set to something other than qmNone. Without a queue there is nothing to drain and the event is never raised.

The handler runs inline on the connection thread and is deliberately not marshalled through NotifyEvents, unlike every other event of this component, so it must not touch the user interface. The deviation is intentional. The whole value of the event is that it runs at that exact point of the connection loop, right after the queue has drained and before the next read, while the socket is still idle, so the application can release the next chunk without waiting. Marshalling it to the main thread would destroy that. Any form, grid or label update has to be marshalled by the application itself, with TThread.Queue, TThread.Synchronize or a message posted to the main thread.

Exceptions raised inside the handler are caught and discarded so that the drain always completes. A handler that fails does so silently, so wrap the body in its own try..except block when a failure has to be reported.

The event fires once per transition from non-empty to empty, not once per pass of the connection loop. It is not a signal that a burst has finished. If the drain keeps pace with a slow producer, every single message can raise its own event, because each message is written out before the next one is enqueued. What the event states is that the queue for this connection is empty right now, nothing more.

The typical use is flow control. When the client streams bulk data, use the event to release the next chunk so the producer follows the speed of the socket instead of filling memory. Pair it with the PendingCount property of TsgcWSConnection, which reports how many messages are still queued for the connection, to run a credit window instead of a stop and wait exchange.

The managed .NET port raises the same event with the same meaning. The one difference is how often it arrives. The Delphi drain runs once per pass of the connection loop, which is Options.ReadTimeOut milliseconds apart and 10 by default, so a slow trickle of messages is coalesced into few events. The managed drain is event driven and the same trickle can raise more events. Bursts behave identically on both.

Example


procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
  // runs on the connection thread, do not touch the user interface here
  Connection.WriteData(GetNextChunk);
end;

Back to Events