TsgcWebSocketServer › Events › OnQueueDrained
Fires when the outbound queue of a client connection goes from holding messages to being empty.
property OnQueueDrained: TsgcWSQueueDrainedEvent;
// TsgcWSQueueDrainedEvent = procedure(Connection: TsgcWSConnection) of object
—
Only fires when message queuing is active for the affected connection, 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 hand out the next credit 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 server relays bulk data between clients, use the event to tell a sending client that it may send more. Pair it with the PendingCount property of TsgcWSConnection, which reports how many messages are still queued for that 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.
procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
// runs on the connection thread, do not touch the user interface here
Connection.WriteData('credit 64');
end;