TsgcWebSocketClient › Événements › OnQueueDrained
Se déclenche lorsque la file d'attente de messages sortants passe de l'état non vide à l'état vide.
property OnQueueDrained: TsgcWSQueueDrainedEvent;
// TsgcWSQueueDrainedEvent = procedure(Connection: TsgcWSConnection) of object
—
Ne se déclenche que lorsque la mise en file d'attente des messages est active, c'est-à-dire lorsque QueueOptions.Text.Level, QueueOptions.Binary.Level ou QueueOptions.Ping.Level a une valeur autre que qmNone. Sans file d'attente, il n'y a rien à vider et l'événement n'est jamais déclenché en mode qdmTransition par défaut.
Le gestionnaire s'exécute en ligne sur le thread de connexion et n'est délibérément pas marshalé via NotifyEvents, contrairement à tous les autres événements de ce composant, il ne doit donc pas toucher à l'interface utilisateur. Cet écart est intentionnel. Tout l'intérêt de l'événement est qu'il s'exécute à ce point précis de la boucle de connexion, juste après que la file d'attente a été vidée et avant la lecture suivante, alors que le socket est encore inactif, de sorte que l'application peut libérer le fragment suivant sans attendre. Le marshaler vers le thread principal détruirait cet avantage. Toute mise à jour d'une fiche, d'une grille ou d'un libellé doit être marshalée par l'application elle-même, avec TThread.Queue, TThread.Synchronize ou un message posté au thread principal.
Les exceptions levées à l'intérieur du gestionnaire sont interceptées et ignorées afin que la vidange se termine toujours. Un gestionnaire qui échoue le fait silencieusement, encadrez donc son corps dans son propre bloc try..except lorsqu'un échec doit être signalé.
La propriété QueueOptions.DrainedMode sélectionne le moment où l'événement est déclenché. Avec qdmTransition (par défaut), il se déclenche une fois par transition de l'état non vide vers l'état vide, comme décrit ci-dessous. Avec qdmEveryPass, il se déclenche à chaque passage de la boucle de connexion, juste après l'envoi des files d'attente, même si la file était déjà vide, et même si Text.Level, Binary.Level et Ping.Level valent tous qmNone, de sorte qu'aucun niveau de file factice n'est nécessaire. Dans ce mode, le gestionnaire est un crochet par connexion sur le thread de connexion, par exemple pour envoyer des données applicatives en attente avec WriteData, afin que chaque écriture sur une connexion s'effectue depuis son propre thread (avec Binary.Level à qmNone, WriteData dans l'événement écrit directement sur le socket). Comme en mode transition, il s'exécute en ligne et ne suit pas NotifyEvents, le gestionnaire doit donc être rapide et ne pas toucher à l'interface utilisateur. Chaque connexion copie les options de file d'attente lors de sa connexion, définissez donc DrainedMode avant d'activer le composant, les connexions déjà ouvertes conservent le mode précédent.
En mode qdmTransition, l'événement se déclenche une fois par transition de l'état non vide vers l'état vide, et non une fois par passage de la boucle de connexion. Ce n'est pas un signal indiquant qu'une rafale est terminée. Si la vidange suit le rythme d'un producteur lent, chaque message peut déclencher son propre événement, car chaque message est écrit avant que le suivant ne soit mis en file d'attente. Ce que l'événement indique, c'est que la file d'attente de cette connexion est vide à cet instant, rien de plus.
L'usage typique est le contrôle de flux. Lorsque le client diffuse des données en masse, utilisez l'événement pour libérer le fragment suivant afin que le producteur suive la vitesse du socket au lieu de saturer la mémoire. Associez-le à la propriété PendingCount de TsgcWSConnection, qui indique combien de messages sont encore en file d'attente pour la connexion, afin de mettre en place une fenêtre de crédit plutôt qu'un échange en mode arrêt et attente.
Le portage .NET managé déclenche le même événement avec la même signification. La seule différence est la fréquence à laquelle il arrive. La vidange Delphi s'exécute une fois par passage de la boucle de connexion, soit toutes les Options.ReadTimeOut millisecondes, 10 par défaut, de sorte qu'un filet lent de messages est regroupé en peu d'événements. La vidange managée est pilotée par les événements et le même filet peut en déclencher davantage. Les rafales se comportent de façon identique dans les deux cas.
procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
// runs on the connection thread, do not touch the user interface here
Connection.WriteData(GetNextChunk);
end;
// qdmEveryPass: runs on every pass of the connection loop
oClient.QueueOptions.DrainedMode := qdmEveryPass;
oClient.QueueOptions.Ping.Level := qmLevel1;
procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
// runs on the connection thread, do not touch the user interface here
if Connection.Disconnected then
exit;
if HasPendingData then
Connection.WriteData(GetPendingData);
end;