TsgcWebSocketClient › Eventos › OnQueueDrained

OnQueueDrained Evento

Disparado quando a fila de mensagens de saída deixa de conter mensagens e fica vazia.

Sintaxe

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

Valor Padrão

—

Observações

Só é disparado quando o enfileiramento de mensagens está ativo, ou seja, quando QueueOptions.Text.Level, QueueOptions.Binary.Level ou QueueOptions.Ping.Level está definido como algo diferente de qmNone. Sem uma fila não há nada para esvaziar e o evento nunca é disparado no modo qdmTransition padrão.

O manipulador é executado em linha na thread da conexão e deliberadamente não é encaminhado através de NotifyEvents, ao contrário de todos os outros eventos deste componente, portanto ele não deve tocar na interface do usuário. O desvio é intencional. Todo o valor do evento está em ser executado exatamente naquele ponto do laço da conexão, logo após a fila ser esvaziada e antes da próxima leitura, enquanto o socket ainda está ocioso, para que a aplicação possa liberar o próximo bloco sem esperar. Encaminhá-lo para a thread principal destruiria isso. Qualquer atualização de formulário, grade ou rótulo precisa ser encaminhada pela própria aplicação, com TThread.Queue, TThread.Synchronize ou uma mensagem enviada à thread principal.

As exceções levantadas dentro do manipulador são capturadas e descartadas para que o esvaziamento sempre seja concluído. Um manipulador que falha o faz silenciosamente, portanto envolva o corpo em seu próprio bloco try..except quando uma falha precisar ser reportada.

A propriedade QueueOptions.DrainedMode seleciona quando o evento é disparado. Com qdmTransition (padrão), ele é disparado uma vez por transição de não vazia para vazia, como descrito abaixo. Com qdmEveryPass, ele é disparado a cada passagem do laço da conexão, logo após o envio das filas, mesmo quando a fila já estava vazia e mesmo quando Text.Level, Binary.Level e Ping.Level são todos qmNone, de modo que não é necessário um nível de fila fictício. Neste modo o manipulador é um gancho por conexão na thread da conexão, por exemplo para enviar dados pendentes da aplicação com WriteData, de modo que toda gravação em uma conexão ocorra a partir da sua própria thread (com Binary.Level definido como qmNone, WriteData dentro do evento grava diretamente no socket). Assim como no modo de transição, ele é executado em linha e não segue NotifyEvents, portanto o manipulador deve ser rápido e não deve tocar na interface do usuário. Cada conexão copia as opções da fila quando se conecta, portanto defina DrainedMode antes de ativar o componente; as conexões já abertas mantêm o modo anterior.

No modo qdmTransition, o evento é disparado uma vez por transição de não vazia para vazia, não uma vez por passagem do laço da conexão. Ele não é um sinal de que uma rajada terminou. Se o esvaziamento acompanhar o ritmo de um produtor lento, cada mensagem pode gerar o seu próprio evento, porque cada mensagem é escrita antes de a seguinte ser enfileirada. O que o evento informa é que a fila desta conexão está vazia neste momento, nada mais.

O uso típico é o controle de fluxo. Quando o cliente transmite grandes volumes de dados, use o evento para liberar o próximo bloco, de modo que o produtor acompanhe a velocidade do socket em vez de encher a memória. Combine-o com a propriedade PendingCount de TsgcWSConnection, que informa quantas mensagens ainda estão enfileiradas para a conexão, para operar uma janela de créditos em vez de uma troca do tipo pare e espere.

A porta gerenciada .NET dispara o mesmo evento com o mesmo significado. A única diferença está na frequência com que ele chega. O esvaziamento do Delphi é executado uma vez por passagem do laço da conexão, com um intervalo de Options.ReadTimeOut milissegundos e 10 por padrão, portanto um fluxo lento de mensagens é agrupado em poucos eventos. O esvaziamento gerenciado é orientado a eventos e o mesmo fluxo lento pode gerar mais eventos. As rajadas se comportam de forma idêntica em ambos.

Exemplo


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;

Voltar para Eventos