有时调用 CompleteAsync 方法时从 Azure 设备客户端抛出 DeviceMessageLockLostException

DeviceMessageLockLostException is thrown from Azure Device Client when calling CompleteAsync method sometimes

我正在尝试从 Azure 设备客户端接收消息,如下所示

public async Task<List<string>> RecieveMessage(string correlationId)
        {
            var response = new List<string>();
            InitializeDeviceClient("AMQP");
            var flag = true;
            while (flag)
            {
                Microsoft.Azure.Devices.Client.Message receivedMessage = await deviceClient.ReceiveAsync(TimeSpan.FromSeconds(120));

                if (receivedMessage == null)
                {
                    await Task.Delay(100).ConfigureAwait(false);
                    continue;
                }

                Trace.WriteLine(receivedMessage.CorrelationId.ToString());
                await this.deviceClient.CompleteAsync(receivedMessage);
                if (receivedMessage.CorrelationId != correlationId)
                {
                    continue;
                }  
               
                var content = Encoding.UTF8.GetString(receivedMessage.GetBytes());
                response.Add(content);
                flag = false;
            }
            return response;
        }

当我根据特定 'CorrelationId' 过滤消息时,我会 return 回复。

在我从 VSTS 运行 调用“CompleteAsync”的步骤中,间歇性地看到异常。

Microsoft.Azure.Devices.Client.Exceptions.DeviceMessageLockLostException: Exception of type 'Microsoft.Azure.Devices.Client.Exceptions.DeviceMessageLockLostException' was thrown.

堆栈跟踪:

Microsoft.Azure.Devices.Client.Transport.AmqpIoT.AmqpIoTOutcome.ThrowIfError()
   at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpTransportHandler.DisposeMessageAsync(String lockToken, AmqpIoTDisposeActions outcome)
   at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.<>c__DisplayClass23_0.<<ExecuteWithErrorHandlingAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.ExecuteWithErrorHandlingAsync[T](Func`1 asyncOperation)
   at Microsoft.Azure.Devices.Client.Transport.RetryDelegatingHandler.<>c__DisplayClass26_0.<<CompleteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Azure.Devices.Client.Transport.RetryDelegatingHandler.CompleteAsync(String lockToken, CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.InternalClient.CompleteAsync(String lockToken)

根据 GH issue#117 and #111,当 C2D 消息的 TTL 在设备确认之前过期时,DeviceMessageLockLostException 是正常操作的一部分。

我会在这里添加推荐:

When you get a DeviceMessageLockLostException, the calling application should just trace it, ignore it and proceed. One of two things will happen:

DeviceClient receives the same message again on ReceiveAsync(). At this point, the DeviceClient can try to complete the message again.

DeviceClient never receives the same message again, in which case no action required anyways.