mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-25 07:41:32 +08:00
Add overflow strategy for pending messages queue.
This commit is contained in:
@@ -6,6 +6,7 @@ namespace MQTTnet.Server
|
||||
{
|
||||
int ConnectionBacklog { get; }
|
||||
int MaxPendingMessagesPerClient { get; }
|
||||
MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; }
|
||||
|
||||
TimeSpan DefaultCommunicationTimeout { get; }
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace MQTTnet.Server
|
||||
// Values described here: [MQTT-3.1.2-24].
|
||||
if (_lastPacketReceivedTracker.Elapsed.TotalSeconds > keepAlivePeriod * 1.5D)
|
||||
{
|
||||
_logger.Warning<MqttClientSession>("Client '{0}': Did not receive any packet or keep alive signal.", _clientId);
|
||||
_logger.Warning(this, null, "Client '{0}': Did not receive any packet or keep alive signal.", _clientId);
|
||||
|
||||
_timeoutCallback?.Invoke();
|
||||
|
||||
@@ -74,11 +74,11 @@ namespace MQTTnet.Server
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error<MqttClientSession>(exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
|
||||
_logger.Error(this, exception, "Client '{0}': Unhandled exception while checking keep alive timeouts.", _clientId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_logger.Verbose<MqttClientSession>("Client {0}: Stopped checking keep alive timeout.", _clientId);
|
||||
_logger.Verbose(this, "Client {0}: Stopped checking keep alive timeout.", _clientId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,25 +50,27 @@ namespace MQTTnet.Server
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DropPacket()
|
||||
{
|
||||
MqttBasePacket packet = null;
|
||||
await _queueWaitSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
if (!_queue.TryDequeue(out packet))
|
||||
{
|
||||
throw new InvalidOperationException(); // should not happen
|
||||
}
|
||||
_queueWaitSemaphore.Release();
|
||||
}
|
||||
|
||||
public void Enqueue(MqttBasePacket packet)
|
||||
{
|
||||
if (packet == null) throw new ArgumentNullException(nameof(packet));
|
||||
|
||||
if (_queue.Count >= _options.MaxPendingMessagesPerClient)
|
||||
{
|
||||
if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropNewMessage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_options.PendingMessagesOverflowStrategy == MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
|
||||
{
|
||||
_queue.TryDequeue(out _);
|
||||
}
|
||||
}
|
||||
|
||||
_queue.Enqueue(packet);
|
||||
_queueAutoResetEvent.Set();
|
||||
|
||||
_logger.Verbose<MqttClientPendingMessagesQueue>("Enqueued packet (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Verbose(this, "Enqueued packet (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
|
||||
private async Task SendQueuedPacketsAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
|
||||
@@ -77,7 +79,7 @@ namespace MQTTnet.Server
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await SendNextQueuedPacketAsync(adapter, cancellationToken).ConfigureAwait(false);
|
||||
await TrySendNextQueuedPacketAsync(adapter, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -85,19 +87,23 @@ namespace MQTTnet.Server
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error<MqttClientPendingMessagesQueue>(exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Error(this, exception, "Unhandled exception while sending enqueued packet (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendNextQueuedPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
|
||||
private async Task TrySendNextQueuedPacketAsync(IMqttChannelAdapter adapter, CancellationToken cancellationToken)
|
||||
{
|
||||
MqttBasePacket packet = null;
|
||||
try
|
||||
{
|
||||
await _queueAutoResetEvent.WaitOneAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (_queue.IsEmpty)
|
||||
{
|
||||
await _queueAutoResetEvent.WaitOneAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!_queue.TryDequeue(out packet))
|
||||
{
|
||||
throw new InvalidOperationException(); // should not happen
|
||||
return;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
@@ -107,24 +113,25 @@ namespace MQTTnet.Server
|
||||
|
||||
await adapter.SendPacketsAsync(_options.DefaultCommunicationTimeout, new[] { packet }, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Verbose<MqttClientPendingMessagesQueue>("Enqueued packet sent (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Verbose<MqttClientPendingMessagesQueue>("Enqueued packet sent (ClientId: {0}).",
|
||||
_clientSession.ClientId);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exception is MqttCommunicationTimedOutException)
|
||||
{
|
||||
_logger.Warning<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed due to timeout (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Warning(this, exception, "Sending publish packet failed: Timeout (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
else if (exception is MqttCommunicationException)
|
||||
{
|
||||
_logger.Warning<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed due to communication exception (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Warning(this, exception, "Sending publish packet failed: Communication exception (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
else if (exception is OperationCanceledException)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error<MqttClientPendingMessagesQueue>(exception, "Sending publish packet failed (ClientId: {0}).", _clientSession.ClientId);
|
||||
_logger.Error(this, exception, "Sending publish packet failed (ClientId: {0}).", _clientSession.ClientId);
|
||||
}
|
||||
|
||||
if (packet is MqttPublishPacket publishPacket)
|
||||
|
||||
@@ -147,10 +147,7 @@ namespace MQTTnet.Server
|
||||
{
|
||||
publishPacket.PacketIdentifier = _packetIdentifierProvider.GetNewPacketIdentifier();
|
||||
}
|
||||
if (_options.MaxPendingMessagesPerClient <= PendingMessagesQueue.Count)
|
||||
{
|
||||
await PendingMessagesQueue.DropPacket();
|
||||
}
|
||||
|
||||
PendingMessagesQueue.Enqueue(publishPacket);
|
||||
}
|
||||
|
||||
@@ -276,7 +273,7 @@ namespace MQTTnet.Server
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
_logger.Warning<MqttClientSession>("Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
|
||||
_logger.Warning(this, null, "Client '{0}': Received not supported packet ({1}). Closing connection.", ClientId, packet);
|
||||
Stop(MqttClientDisconnectType.NotClean);
|
||||
|
||||
return Task.FromResult(0);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
public enum MqttPendingMessagesOverflowStrategy
|
||||
{
|
||||
DropOldestQueuedMessage,
|
||||
DropNewMessage
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,9 @@ namespace MQTTnet.Server
|
||||
public int ConnectionBacklog { get; set; } = 10;
|
||||
|
||||
public int MaxPendingMessagesPerClient { get; set; } = 250;
|
||||
|
||||
|
||||
public MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; set; } = MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage;
|
||||
|
||||
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(15);
|
||||
|
||||
public Action<MqttConnectionValidatorContext> ConnectionValidator { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user