我正在尝试实现一个监视长时间运行的SQL存储过程的过程。我的代码在执行存储过程的SqlCommand上调用BeginExecuteReader()。然后,我在循环中轮询IAsyncResult.IsCompleted值。在线所有文献都说,仅当存储过程完成执行时,IsCompleted才设置为true。 但是我发现它几乎立即将其标记为true,退出循环。然后,当我调用EndExecuteReader()时,线程将阻塞,因为存储过程仍在运行。
IAsyncResult是否存在一些已知问题。是否已按预期方式工作?
值得一提的是,所讨论的存储过程调用了许多子存储过程。这些消息均写入控制台窗口(我的代码通过InfoMessage事件提取这些消息)。但是,SP不会在IsCompleted正在标记的点返回结果集。
private static void runEtlLoadStoredProcedure(EtlState etlState, ConcurrentBag<EtlError> errors) {
using (var executingUc = etlState.Context.CreateNewUserContext()) { // Create a separate UserContext and SqlConnection so we can concurrently read and write to DB
executingUc.SqlConn.InfoMessage += (sender, args) => SqlConn_InfoMessage(sender, args, etlState); // Event handler when messages are generated by the ETL Stored Procedure
using(SqlCommand command = new SqlCommand(EtlConfig.StagingToLiveStoredProcedure, executingUc.SqlConn) { CommandType = CommandType.StoredProcedure }) {
var asyncResult = command.BeginExecuteReader();
monitorUntilComplete(etlState, executingUc.SqlConn, command, asyncResult, errors); // Will periodically check for cancellation, waiting until the SP call has finished
using(SqlDataReader reader = command.EndExecuteReader(asyncResult)) { // Get any result sets returned by the ETL SP
}
}
}
}
private static void monitorUntilComplete(EtlState etlState, SqlConnection executingConn, SqlCommand sqlCommand, IAsyncResult asyncResult, ConcurrentBag<EtlError> errors) {
while (!asyncResult.IsCompleted) {
System.Threading.Thread.Sleep(EtlConfig.StagingToLivePollingIntervalMs); // Wait for a period of time
int x = 0; // Test
Debug.WriteLine("waiting");
}
int y = 1;
}
更新:
使用BeginExecuteNonQuery而不是Reader时,结果没有任何变化。当我删除SqlConnection.InfoMessage事件时,也没有任何变化。 切换到 ExecuteNonQueryAsync 可行;可以轮询Task对象,直到完成。但是,使用此函数时,不会触发SqlConnection.InfoMessage事件,因此这产生了一个新问题。
有人知道吗?