我有一个通过RabbitMQ接收消息的Windows服务,这会触发一个事件处理程序,它会执行一些工作,然后尝试将结果保存到数据库中。它的线程使用:
ThreadPool.QueueUserWorkItem(ProcessMessageOnThread, messageReceived);
其中ProcessMessageOnThread
是一个在messageReceived
上工作的方法,它是从RabbitMQ出列的消息的表示。
在正常情况下,Windows服务按预期运行,即出列,处理和持续。
我想确保处理所有邮件并给予公平更改以便处理,因此如果我无法打开与SQL Server的连接,我只需将邮件重新排列以便再次处理(希望那时候SQL Server将返回,否则这将继续 - 我很好。
现在问题出现了,当进程按预期运行一段时间后,SQL Server连接池已经填满,然后然后 SQL Server断开连接,现在这就是有点不稳定。
可能发生以下两件事之一:
connection.Open()
引发了异常 - 但是我抓住了这个,所以不担心它
在cmd.ExecuteNonQuery()
上抛出异常 - 这是我正在执行存储过程的地方
这是我需要弄清楚如何处理的第二个选项。以前我认为这里的任何异常都意味着我传入存储过程的数据存在问题,因此应该将其移出队列并进行其他分析。
然而,现在我认为我需要一种新方法来处理异常与未实际建立的连接有关的情况。
我查看了SqlException
类,发现了一个名为Class
的属性,其中包含此描述Gets the severity level of the error returned from SQL Server
,现在有关此信息的说明:
严重性级别为10或更低的邮件是信息性的,表示用户输入的信息错误导致的问题。用户生成从11到16的严重级别,并且可以由用户进行更正。严重级别从17到25表示软件或硬件错误。当发生级别17,18或19错误时,您可以继续工作,尽管您可能无法执行特定语句。
这是否意味着修复我的异常处理我可以检查if (ex.Class > 16)
然后重新排队消息,因为问题在于连接else
将其丢弃,因为它最有可能发送格式错误的数据到存储过程?
所以问题是,我应该如何进行异常处理?如果由于连接断开而抛出异常,如何在调用cmd.ExecuteNonQuery()
时检测到。
更新
我之前遇到过没有返回池的连接问题(这是由于线程问题)并修复了这些问题,所以我有信心这个问题与没有重新进入连接的连接无关。池。此外,围绕什么连接使用的逻辑是如此简单,我也确保它们一致地关闭...所以我更感兴趣的是关于断开Sql Server然后捕获行为的答案of cmd.ExecuteNonQuery()
答案 0 :(得分:3)
由于各种原因,连接池中的连接可能会进入一种奇怪的状态,所有这些都与糟糕的应用程序设计有关:
BeginOpenReader
),然后在异步处理程序触发之前将连接返回到池您应该调查您的应用程序并确保连接正确返回到池中。有助于调试的一件事是减少开发设置中应用程序池的大小。您可以在连接字符串中更改池的大小:
...;Integrated Security=SSPI;Max Pool Size=2;Pooling=True;
这使得汇集问题更容易重现。
如果找不到原因,但仍需要部署修复程序,则可以使用ClearPool
或ClearAllPools
之一。这样做的好地方是在Open()
或ExecuteNonQuery()
之后发现一个可疑异常时。两者都是SqlConnection
类的静态方法:
SqlConnection.ClearPool(yourConnection);
或者采取更粗糙的方法:
SqlConnection.ClearAllPools()
请注意,这基本上是Pokémon Exception Handling。如果它有效,你将不知道为什么。 :)