Azure EventHub - EventHubClient.Send() 导致 NullReferenceException

Azure EventHub - EventHubClient.Send() results in NullReferenceException

简短版本:NullReferenceException 使用 EventHubClient.SendBatch 将数据发送到 EventHub。为什么连接被断开?

更长的解释:

我正在尝试使用 C# 中 EventHubClient class 的 SendBatch 方法将数据发送到 EventHub。 (https://docs.microsoft.com/en-us/dotnet/api/microsoft.servicebus.messaging.eventhubclient)

批量大小为 100 个 json 个对象,不应太大。我在更大和更小的批量大小上都遇到过同样的问题。我也试过使用 Send() 来一个一个地发送对象。同样的结果。

这在 99% 的情况下都很好,但有时会导致 NullReferenceException,留下以下堆栈跟踪:

System.NullReferenceException: Object reference not set to an instance of an object.
    at Microsoft.ServiceBus.Messaging.MessageSender.RetrySenderEventDataAsyncResu
    lt.<>c.<.ctor>b__5_0(EventData e)
      at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate
    )
      at Microsoft.ServiceBus.Messaging.MessageSender.RetrySenderEventDataAsyncResu
    lt..ctor(MessageSender sender, TrackingContext trackingContext, IEnumerable`1 me
    ssages, TimeSpan timeout, AsyncCallback callback, Object state)
      at Microsoft.ServiceBus.Messaging.MessageSender.BeginSendEventData(TrackingCo
    ntext trackingContext, IEnumerable`1 eventDatas, TimeSpan timeout, AsyncCallback
    callback, Object state)
      at Microsoft.ServiceBus.Messaging.EventHubClient.SendBatch(IEnumerable`1 even
    tDataList)

我尝试实施重试政策,两者都使用 EventHubClient.RetryPolicy = RetryPolicy.Default; 并通过使用 Thread.Sleep(n) 手动执行递归方法调用,以提供重新建立连接的时间。

有时连接会在 10 秒后恢复,有时会在 60 秒后恢复,通常永远不会(或者直到我对该方法的递归调用达到 WhosebugException,大约 30 分钟后,但取决于多长时间线程进入休眠状态)。从逻辑上讲,我的系统不能有这个不稳定的部分。

任何人都知道为什么会发生此异常,是否是由于连接断开?

这里的答案竟然是一个重载的EventHub。

每第 100 个批次,等待 0.5 秒。对于每个 NullReferenceException,请等待 2 秒,然后再尝试使用相同的数据。在连接恢复之前,可能需要重试 100 多次。我尝试了指数等待时间,但在我的案例中没有成功(最终等待了几个小时,但仍然没有连接)。

当然 - 在 C# 中使用永恒的 while 循环而不是递归调用。这可以防止 WhosebugException。 (菜鸟错误)。

工作代码:

public bool SendMessageAsList(List<EventData list) 
{
while(true)
{
    var batchList = new List<EventData>();
    for (var i = 0; i < list.Count; i + 100)
    try
    {
        if (i % 10000)
            Thread.Sleep(500);
        batchList = list.Skip(i).Take(100).ToList();
        EventHubClient.SendBatch(batchList);
        // Gets here at success
        list = list.Skip(100).ToList();
        if (batchList.Count < 100)
            break;
    }
    catch (NullReferanceException e)
    {
        Console.WriteLine(e);
        Thread.Sleep(2000)
}
}