【发布时间】:2018-01-16 19:46:01
【问题描述】:
我们使用 SQL Service Broker 队列来通知我们的应用程序符合某些条件的新记录被添加到另一个应用程序的数据库中的表中。这是通过让after insert 触发器使用for xml 对inserted 虚拟表运行查询并将任何结果插入特定的服务代理队列来实现的。然后我们有一个Notifier 对象,它从服务代理队列接收并为收到的每条消息调用回调。我们从 Service Broker 队列接收的代码如下:
let receiveXmlMessage connection transaction (cancellation: CancellationToken) queueName messageTypeName =
task {
let commandTimeout = if cancellation.IsCancellationRequested then 1 else 0
let receiveQuery =
sprintf """WAITFOR
(
RECEIVE TOP(1)
@message = CONVERT(xml, message_body),
@messageType = message_type_name,
@dialogId = conversation_handle
FROM dbo.[%s]
), TIMEOUT 60000;""" (sanitize queueName)
use receiveCommand =
match transaction with
| Some tx -> new SqlCommand(receiveQuery, connection, tx, CommandTimeout = commandTimeout)
| None -> new SqlCommand(receiveQuery, connection, CommandTimeout = commandTimeout)
receiveCommand.Parameters.AddRange([| SqlParameter("@message", SqlDbType.Xml, Direction = ParameterDirection.Output);
SqlParameter("@messageType", SqlDbType.NVarChar, Direction = ParameterDirection.Output, Size = 256);
SqlParameter("@dialogId", SqlDbType.UniqueIdentifier, Direction = ParameterDirection.Output); |])
try
let! receiveResult = receiveCommand.ExecuteNonQueryAsync(if commandTimeout = 0 then cancellation else CancellationToken.None)
if receiveResult > 0
then let messageType = receiveCommand.Parameters.["@messageType"].Value |> unbox<string>
let dialogId = receiveCommand.Parameters.["@dialogId"].Value |> unbox<Guid>
if messageType = messageTypeName
then do! endConversation connection transaction dialogId
return receiveCommand.Parameters.["@message"].Value |> unbox<string> |> XDocument.Parse
else return XDocument()
else return XDocument()
with | ex ->
log.errorxf ex "Failed to receive message from Service Broker Queue %s" queueName
return! Task.FromException ex
}
这几个月运行良好,处理了数百万条消息,直到几天前,当我们有另一个进程导致我们监控的数据库出现广泛阻塞时,我们的 DBA 不得不终止几个数据库会话以缓解争用。自此事件以来,我们的应用程序在尝试从 Service Broker 队列接收时遇到以下错误:
2018-01-11 07:50:27.183-05:00 [31] ERROR - Failed to receive message from Service Broker Queue Notifier_Queue
System.Data.SqlClient.SqlException (0x80131904): A severe error occurred on the current command. The results, if any, should be discarded.
Operation cancelled by user.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.CompleteAsyncExecuteReader()
at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult)
at System.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Application.Common.Sql.ServiceBroker.receiveXmlMessage@257-3.Invoke(Unit unitVar0)
at Application.Common.TaskBuilder.tryWith[a](FSharpFunc`2 step, FSharpFunc`2 catch)
新消息已成功添加到队列中,我们可以使用 SSMS 接收来自同一队列的消息,甚至可以以与应用程序相同的用户身份运行 F# 交互式会话。它似乎只是我们的应用程序受到影响,但它似乎确实影响了我们应用程序的所有实例,在不同的服务器上,只要它们连接到这个特定的数据库。我们尝试重新启动应用程序和 SQL Server,并尝试运行ALTER DATABASE ... SET NEW_BROKER WITH ROLLBACK IMMEDIATE。我们尝试过的任何事情都没有改变,我们最终还是遇到了同样的异常,并且我们有数十万个对话保持CONVERSING 状态,因为我们调用END CONVERSATION 的代码只有在成功接收到消息后才会被调用.
我们的 SQL Service Broker 队列设置为对 this blog post 中所述的独白模式进行建模。
我们如何诊断我们的应用程序从 SQL Server 返回的这个相当非特定的异常的原因?当问题首次出现时,我们是否可以尝试诊断和/或更正我们的应用程序和 SQL Service Broker 之间的任何变化?
【问题讨论】:
标签: sql .net sql-server f# service-broker