SQLDependency.Stop()-调用,但当QN订阅超时时,会在队列中丢弃一条消息
本文关键字:队列 消息 一条 超时 Stop 调用 QN 但当 SQLDependency | 更新日期: 2023-09-27 18:29:52
场景
- 静态Service Broker队列和服务
- 将这些静态队列用于SQLDependency订阅
代码的大致轮廓
使用这篇博客文章作为模板,代码大致遵循以下模式
- 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,根据文档,这意味着侦听器已完全停止
面临的问题
然后我看到的是,当订阅达到超时期时,它会触发并将一条消息放到等待消耗的依赖队列中。
如果这些消息留在队列中,则在下次启动时,应用程序会抛出给定的键不在字典中
此外,如果我调用SQLDependency.Stop()并保持应用程序运行,它仍然会消耗QN触发的超时。
我错过了什么步骤,因为如果消息被丢弃在静态队列上,导致字典异常中不存在给定的密钥,我可能会遇到问题。
感谢
这返回true,根据文档,这意味着侦听器已完全停止。
这对服务器状态和队列状态都没有任何承诺。这些将比您的易失性应用程序状态更持久,在下次启动时,您将发现应用程序脱机/关闭时的通知。您将不得不进行相应的编码,并保持这种期望(例如,忽略字典中没有的键)。
请注意,即使SqlDependency.Stop()
尝试停止挂起的订阅通知,也无法保证成功,因为可能有通知正在传输(即,通过Service Broker挂起的传递,通知可能在sys.transmission_queue
中)。等待所有在途通知耗尽交付也是不可行的。
此外,您的应用程序将无法像现在这样处理备份还原场景。已还原的备份可能包含挂起的通知请求,这些请求将在还原并激发通知消息时失效。当应用程序连接时,它会发现那些意外的通知。
最终,应用程序将无法处理自己的断开连接/崩溃。如果你依靠SqlDependency.Stop()
才能成功,那么如果你不能调用SqlDependency.Stop()
(=>任何不优雅的停止),你就根本无法启动。
由于所有这些原因,必须能够处理字典中没有的键。