1

.Net 代码如何检测 SQL 服务器何时决定卸载 AppDomain?

SQL 服务器有时会出于各种原因决定卸载 AppDomain,将其状态更改sys.dm_clr_appdomainsE_APPDOMAIN_DOOMED

AppDomain 计划卸载,但当前有线程在其中执行。

当“计划卸载 AppDomain”或在 CLR 代码中检测此状态的方法时,CLR 代码中是否会引发事件?

如果我知道代码作为哪个 AppDomain 执行,我可以定期轮询状态sys.dm_clr_appdomains,但这不会在SqlContext对象中公开。我不确定是否sys.dm_clr_appdomains.assembly_nameAppDomain.FriendlyName.

如果可能的话,我已经存储了永远运行的过程(当数据可用时,它们会将数据推送到客户端)。由于当 SQL Server 决定卸载 AppDomain 时这些线程仍在运行,因此 AppDomain 永远不会卸载,线程永远不会停止执行,来自客户端的连接永远不会关闭。

编辑:

匹配中的 and ,appdomain_idappdomain_name使用以下 CLR 存储过程进行了检查:sys.dm_clr_appdomainsSystem.AppDomain.IdSystem.AppDomain.FriendlyName

public static class Status
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void GetAppDomain()
    {
        var record = new SqlDataRecord(
            new SqlMetaData("ID", SqlDbType.Int),
            new SqlMetaData("FriendlyName", SqlDbType.VarChar, 386));
        SqlContext.Pipe.SendResultsStart(record);

        record.SetInt32(0, AppDomain.CurrentDomain.Id);
        record.SetString(1, AppDomain.CurrentDomain.FriendlyName);
        SqlContext.Pipe.SendResultsRow(record);

        SqlContext.Pipe.SendResultsEnd();
    }
}

因此,在等待下一个事件超时后轮询状态绝对是可能的,但它会留下与程序集状态的最大轮询频率相关的不希望的延迟量。

编辑2:

AppDomain.DomainUnload更改为其创建 AppDomain 的程序集时不会引发该事件。我不知道当 Sql Server 决定卸载 AppDomain 时是否会引发它。

    private static readonly WaitHandle unloadEvent = MakeUnloadEvent();

    private static WaitHandle MakeUnloadEvent() {
        var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

        AppDomain.CurrentDomain.DomainUnload += (sender, args) => {
            waitHandle.Set();
        };

        return waitHandle;
    }

    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void OnUnload()
    {
        unloadEvent.WaitOne();

        var record = new SqlDataRecord(
            new SqlMetaData("Done", SqlDbType.Bit));

        SqlContext.Pipe.SendResultsStart(record);
        record.SetBoolean(0, true);
        SqlContext.Pipe.SendResultsRow(record);
        SqlContext.Pipe.SendResultsEnd();
    }

运行OnUnloadsproc 然后更改程序集会导致ALTER ASSEMBLY命令挂起或 AppDomain 在没有引发事件的情况下注定失败。

4

1 回答 1

1

我会假设sys.dm_clr_appdomains.appdomain_id直接映射到System.AppDomain.ID. 你试过用这个吗?

另一种可能性是AppDomain.DomainUnloaded事件。我无法测试 SQL Server 卸载域时是否会触发此操作。

于 2014-03-20T17:24:50.763 回答