SQLDependency.Stop()-已调用,但是当QN订阅超时时,一条消息被丢弃在队列中

问题描述 投票:0回答:1

场景

  • 静态服务代理队列和服务
  • 使用这些静态队列进行SQLDependency预订

代码概要

使用this blog post作为模板,代码大致遵循此模式

  • SqlDependency.Start(this.dbConnectionString,this.notificationQueueName);
  • 配置特定于服务的依赖关系(请参见下面的代码)

        private async void ConfigureDependencyUsingStoreProcedureAndSpecificQueue()
        {
            if (null != this.sampleSqlDependency)
            {
                this.sampleSqlDependency.OnChange -= null;
            }
    
            if (null != this.sampleSqlCommand)
            {
                this.sampleSqlCommand.Dispose();
            }
    
            if (null != this.sampleSqlConnection)
            {
                this.sampleSqlConnection.Dispose();
            }
    
            this.sampleSqlDependency = null;
            this.sampleSqlCommand = null;
            this.sampleSqlConnection = null;
    
            //// Create connection.
            this.sampleSqlConnection = new SqlConnection(this.dbConnectionString);
    
            //// Create command.
            this.sampleSqlCommand = new SqlCommand { Connection = this.sampleSqlConnection };
            this.sampleSqlCommand.CommandType = CommandType.StoredProcedure;
            this.sampleSqlCommand.CommandText = this.notificationStoredProcedure;
            this.sampleSqlCommand.Notification = null;
    
            //// Create Sql Dependency.
            this.sampleSqlDependency = new SqlDependency(this.sampleSqlCommand, "service=" + this.notificationServiceName +"; Local database=" + this.databaseName, this.notificationTimeout);
            this.sampleSqlDependency.OnChange += this.SqlDependencyOnChange;
            await this.sampleSqlCommand.Connection.OpenAsync();
            await this.sampleSqlCommand.ExecuteReaderAsync(CommandBehavior.CloseConnection);
    
            if (null != this.sampleSqlCommand)
            {
                this.sampleSqlCommand.Dispose();
            }
    
            if (null != this.sampleSqlConnection)
            {
                this.sampleSqlConnection.Dispose();
            }
    
  • 处理SqlDependencyOnChange事件,如下所示。再次调用ConfigureDependency代码

    private void SqlDependencyOnChange(object sender, SqlNotificationEventArgs eventArgs)
    {
        if (eventArgs.Info == SqlNotificationInfo.Invalid)
        {
            Console.WriteLine("The above notification query is not valid.");
        }
        else
        {
            Console.WriteLine("\nNotification Time: {0}", DateTime.Now);
            Console.WriteLine("\nNotification Info: " + eventArgs.Info);
            Console.WriteLine("Notification source: " + eventArgs.Source);
            Console.WriteLine("Notification type: " + eventArgs.Type + "\n");
        }
    
         switch (optionSelected)
            {
                case "1":
                    this.ConfigureDependencyUsingStoreProcedureAndDefaultQueue();
                    break;
                case "2":
                    this.ConfigureDependencyUsingStoreProcedureAndSpecificQueue();
                    break;
                case "3":
                    this.ConfigureDependencyUsingTextQueryAndDefaultQueue();
                    break;
                case "4":
                    this.ConfigureDependencyUsingTextQueryAndSpecificQueue();
                    break;
            }
    }
    
  • 在应用程序关闭时调用SqlDependency.Stop(this.dbConnectionString,this.notificationQueueName);。返回true,根据documentation表示监听器已完全停止。

面临问题

然后我看到的是,当订阅达到其超时期限时,它会触发并向依赖项队列中发送一条消息,等待被消耗。

如果这些消息留在队列中,则下次启动时,应用程序将引发给定的键在词典中不存在。

此外,如果我调用SQLDependency.Stop()并保持应用程序运行,它仍然会消耗QN触发超时。

我在这里缺少什么步骤,因为如果消息被丢弃到静态队列上导致给定键在词典中不存在异常,我很可能会遇到问题。

谢谢

c# sql-server notifications sqldependency
1个回答
0
投票

这将返回true,根据文档,这意味着侦听器已完全停止。

这不保证server状态,也不保证队列状态。这些将使您的应用程序状态不稳定,并且在下次启动时,您查找有关您的应用程序离线/关机的通知。您将必须进行相应的编码,并具有适当的期望(例如,忽略不在词典中的键)。

请注意,即使SqlDependency.Stop()试图停止待处理的订阅通知,也无法保证成功,因为可能会有通知传输中(即,通过Service Broker进行待处理的传递,通知可能位于[C0 ])。等待所有运输中的通知耗尽交货也不可行。

此外,您的应用程序将无法像现在一样处理备份-还原方案。恢复的备份可能包含待处理的通知请求,这些请求将在恢复后失效并触发通知消息。当应用程序连接时,它将发现那些意外的通知。

并且最终,该应用程序将无法处理其自身的断开连接/崩溃。如果您依靠sys.transmission_queue成功才能在下一次成功启动,那么即使您无法调用SqlDependency.Stop()(=>任何非平稳停止),也将无法启动。

由于所有这些原因,您必须能够处理不在词典中的键。

© www.soinside.com 2019 - 2024. All rights reserved.