Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ServiceBus SubscriptionClient更新锁定错误_C#_Azure_.net Core_Azureservicebus_Servicebus - Fatal编程技术网

C# 使用ServiceBus SubscriptionClient更新锁定错误

C# 使用ServiceBus SubscriptionClient更新锁定错误,c#,azure,.net-core,azureservicebus,servicebus,C#,Azure,.net Core,Azureservicebus,Servicebus,我正在.net Core 2.1中编写一个控制台应用程序,我的目的是监听ServiceBus中某个主题的消息,并使用NEST api处理到达Elasticsearch的新消息(NEST可能与我的问题无关,但希望透明) 我在ServiceBus中的主题实体称为“test”,我有一个订阅,也称为“test”(完整路径为“test/subscriptions/test”) 在我的.net Core控制台应用程序中,我有以下NuGet参考: <PackageReference Include="M

我正在.net Core 2.1中编写一个控制台应用程序,我的目的是监听ServiceBus中某个主题的消息,并使用NEST api处理到达Elasticsearch的新消息(NEST可能与我的问题无关,但希望透明)

我在ServiceBus中的主题实体称为“test”,我有一个订阅,也称为“test”(完整路径为“test/subscriptions/test”)

在我的.net Core控制台应用程序中,我有以下NuGet参考:

<PackageReference Include="Microsoft.Azure.ServiceBus" Version="3.2.1" />
<PackageReference Include="NEST" Version="6.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />

我在使用.net标准ServiceBus Api时遇到了一个非常奇怪的问题,我经常会遇到续订锁错误:

消息处理程序遇到异常 Microsoft.Azure.ServiceBus.MessageLockLostException

我已将我的代码剥离回一个非常可复制的示例:

using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Elasticsearch.Net;
using Microsoft.Azure.ServiceBus;
using Nest;
using Newtonsoft.Json;

namespace SampleApp
{
    public class Program
    {

    private static SubscriptionClient _subscriptionClient;
    private static IElasticClient _elasticClient;

    private static string ServiceBusConnectionString = "[connectionString]";
    private static string TopicName = "test";
    private static string SubscriptionName = "test";

    public static void Main(string[] args)
    {
        var elasticsearchSettings = new ConnectionSettings(new SingleNodeConnectionPool(new Uri("http://does.not.exist:9200"))).DefaultIndex("DoesNotExistIndex");
        _elasticClient = new ElasticClient(elasticsearchSettings);

        _subscriptionClient = new SubscriptionClient(ServiceBusConnectionString, TopicName, SubscriptionName);

        // Configure the message handler options in terms of exception handling, number of concurrent messages to deliver, etc.
        var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
        {
            // Maximum number of concurrent calls to the callback ProcessMessagesAsync(), set to 1 for simplicity.
            // Set it according to how many messages the application wants to process in parallel.
            MaxConcurrentCalls = 1,
            MaxAutoRenewDuration = TimeSpan.FromSeconds(400),
            // Indicates whether the message pump should automatically complete the messages after returning from user callback.
            // False below indicates the complete operation is handled by the user callback as in ProcessMessagesAsync().
            AutoComplete = false
        };

        // Register the function that processes messages.
        _subscriptionClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);

        Console.WriteLine("INFO: Process message handler registered, listening for messages");
        Console.Read();
    }

    private static async Task ProcessMessagesAsync(Message message, CancellationToken token)
    {
        // Message received.
        var content = Encoding.UTF8.GetString(message.Body);

        var messageBody = JsonConvert.DeserializeObject<string[]>(content);

        Console.WriteLine($"INFO: Message arrived: {message}");
        Console.WriteLine($"INFO: Message body: \"{string.Join(",", messageBody)}\"");
        try
        {
            var response = _elasticClient.Ping();

            if (!response.IsValid && response.OriginalException != null)
                Console.WriteLine($"ERROR: ElasticSearch could not be reached, error was \"{response.OriginalException.Message}\"");
            else
                Console.WriteLine("INFO: ElasticSearch was contacted successfully");
        }
        catch (Exception e)
        {
            Console.WriteLine("!ERROR!: " + e);
        }

        await _subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
        Console.WriteLine("INFO: Message completed");
    }

    // Use this handler to examine the exceptions received on the message pump.
    private static Task ExceptionReceivedHandler(ExceptionReceivedEventArgs exceptionReceivedEventArgs)
    {
        Console.WriteLine($"Message handler encountered an exception {exceptionReceivedEventArgs.Exception}: " +
                          $"{exceptionReceivedEventArgs.ExceptionReceivedContext.Action}: " +
                          $"{exceptionReceivedEventArgs.ExceptionReceivedContext.EntityPath}");
        return Task.CompletedTask;
    }

}
使用系统;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用Elasticsearch.Net;
使用Microsoft.Azure.ServiceBus;
利用鸟巢;
使用Newtonsoft.Json;
名称空间SampleApp
{
公共课程
{
专用静态SubscriptionClient _SubscriptionClient;
私有静态IElasticClient(弹性客户端);
私有静态字符串ServiceBusConnectionString=“[connectionString]”;
私有静态字符串TopicName=“test”;
私有静态字符串SubscriptionName=“test”;
公共静态void Main(字符串[]args)
{
var elasticsearchSettings=新的连接设置(新的SingleNodeConnectionPool(新的Uri)(“http://does.not.exist:9200DefaultIndex(“DoesNotExistIndex”);
_elasticClient=新的elasticClient(elasticsearchSettings);
_subscriptionClient=新的subscriptionClient(ServiceBusConnectionString、TopicName、SubscriptionName);
//根据异常处理、要传递的并发消息数等配置消息处理程序选项。
var messagehandler options=新的messagehandler选项(例外ReceivedHandler)
{
//对回调ProcessMessagesAsync()的最大并发调用数,为简单起见设置为1。
//根据应用程序希望并行处理的消息数量设置。
MaxConcurrentCalls=1,
MaxAutoRenewDuration=时间跨度从秒(400),
//指示消息泵是否应在从用户回调返回后自动完成消息。
//下面的False表示整个操作由用户回调处理,如ProcessMessagesAsync()中所示。
自动完成=错误
};
//注册处理消息的函数。
_RegisterMessageHandler(ProcessMessagesSync、messageHandlerOptions);
WriteLine(“信息:进程消息处理程序已注册,正在侦听消息”);
Console.Read();
}
专用静态异步任务ProcessMessagesAsync(消息消息、取消令牌)
{
//收到消息。
var content=Encoding.UTF8.GetString(message.Body);
var messageBody=JsonConvert.DeserializeObject(内容);
WriteLine($“信息:消息到达:{Message}”);
Console.WriteLine($“INFO:messageBody:\”{string.Join(“,”,messageBody)}\”);
尝试
{
var response=_elasticClient.Ping();
如果(!response.IsValid&&response.OriginalException!=null)
WriteLine($”错误:无法访问ElasticSearch,错误为\“{response.OriginalException.Message}\”);
其他的
Console.WriteLine(“信息:已成功联系ElasticSearch”);
}
捕获(例外e)
{
Console.WriteLine(“!ERROR!:”+e);
}
wait_subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
Console.WriteLine(“信息:消息已完成”);
}
//使用此处理程序检查在消息泵上接收到的异常。
专用静态任务例外ReceivedHandler(例外ReceivedEventArgs例外ReceivedEventArgs)
{
Console.WriteLine($“消息处理程序遇到异常{exceptionReceivedEventArgs.exception}:”+
$“{exceptionReceivedEventArgs.ExceptionReceivedContext.Action}:”+
$“{exceptionReceivedEventArgs.ExceptionReceivedContext.EntityPath}”);
返回Task.CompletedTask;
}
}
此代码与下面的示例几乎相同:

我故意“ping”一个不存在的Elasticsearch实例,以生成套接字异常,帮助我重现问题

我注意到的一件事是,当我创建一个新主题并启用parting=false时,问题不会发生

以前有人见过吗?这似乎是ServiceBus代码本身的一个深层问题

注意:我尝试使用接收器使用“ReceiveAsync”读取消息,在这种情况下也会出现此错误。此外,我的测试驱动程序将从.net Framework ServiceBus客户端(它与分区一起工作)转移到.net核心版本


提前感谢您的指点!!

我建议您在订阅
MaxAutoRenewDuration=TimeSpan.FromSeconds(xxxx)
中设置更高的锁定持续时间,或者您可以使用
message.RenewLock()


希望能有所帮助!

在我上面的例子中,问题在于对我的配置有一点误解。 在Azure中,如果您导航到:

资源组>服务业务实例>主题>测试主题>测试订阅

您可以找到订阅属性。在这里,您将看到发送消息时锁定的持续时间。这默认为60秒,但我将长时间运行的过程延长到最多5分钟,如下所示:

然后在代码中,当为我的订阅连接属性时
sbNamespace.Topics.GetByName(“test”).Subscriptions.GetByName(“test”).LockDurationInSeconds