4

私のSqlDependencyは正常に動作し、アプリケーションの終了時に Broker Queue と Service が適切に削除されます (プロセスを終了する前に推奨どおりにSqlDependency.Stop(...)を実行します) が、 SqlDependencyによって作成された通知サブスクリプションが存続していることに気付きましたアプリケーションがシャットダウンした後、テーブル「sys.dm_qn_subscriptions」でオンになります。

後で (アプリのシャットダウン後)、このサブスクリプションを起動する必要がある条件を実行すると、SQL Server がイベント ビューアーに情報メッセージを記録して、次のような効果があるため、起動したように見えます。

'{3F03B693-C0A5-E211-A97B-E06995EBDB20}.'次のエラーのため、会話ハンドルのクエリ通知ダイアログが 閉じられました: '<?xml version="1.0"?><Error xmlns="http://schemas.microsoft.com/SQL/ServiceBroker/Error"><Code>-8490</Code><Description>Cannot find the remote service &apos;SqlQueryNotificationService-0ea1f686-e554-4e25-aa7d-4f6d85171cc3&apos; because it does not exist.</Description></Error>'

その後、サブスクリプションは「sys.dm_qn_subscriptions」から削除されます。

注: サブスクリプションは、アプリケーションが有効な場合にも適切に起動します。私のアプリケーションに関する限り、何も問題はありませんが、サブスクリプションが依存するブローカー キュー/サービスが終了すると、データベース システム テーブルでサブスクリプションが自動的にワイプされないことが心配です。これにより、(少なくとも) 大量のファントム/アンデッド サブスクリプション レコードがデータベースに蓄積され、イベント ビューアーに不要な SQL Server クリーンアップ メッセージが表示される可能性があります (アプリを実行するたびに、"sys.dm_qn_subscriptions" に新しいアンデッド レコードが生成されます)。

この動作は正常ですか?物事をよりきれいにすることはできますか?

4

2 に答える 2

4

これは正常な動作です。QN は存続期間が長く、データベースの再起動時に起動します (したがって、サーバーの再起動後にも起動します)。ただし、通知を受信するために一時的なサービス/キューを設定します。これらは、ダイアログ タイマー内部アクティベーションSqlDependencyを使用して、クラッシュの場合に破棄することになっています。これら 2 つのメカニズムが相互作用する方法は、ご覧のとおり、ERRORLOG 汚染です。少なくとも通常は何も悪いことは起こりませんが、明らかにきれいではありません。

物事をよりきれいにすることはできますか?

appdomain 通知を受信して​​適切なイベントSqlNotificationRequestにルーティングするサービス/キューを作成する「サービス」を提供しなくなった直接使用して、独自のソリューションを展開できます。SqlDependency.OnChange正確なシナリオに応じて、実行可能な代替手段があります。しかし、かなり低レベルの作業であり、元のSqlDependencyソリューションよりも悪い方法で問題を解決することになる可能性があります...

ところで、アプリケーションの終了時に保留中の QN サブスクリプションを「ドロップ」する方法はありません。この問題は、QN によって通知配信メカニズムとして使用される一方向ダイアログに固有のものです。適切な通知 (サブスクリプション) はサブスクライバーによって開始される必要があり、通知はターゲット (ノーティファイアー) からイニシエーター (サブスクライバー) への応答メッセージである必要があります。

于 2013-04-15T14:05:59.280 に答える
0

少し安っぽくても構わないのであれば、終了時にこれらをクリーンアップする方法を見つけました...

最初に、onDependencyChange が監視できるフラグを設定して、クエリを再サブスクライブしないように通知します。

次に、フラグを設定し、依存関係サブスクリプションをトリガーすることがわかっている何もしない更新を実行します。

 update foo_master set foo_bar = foo_bar where foo_id = @id;

私の依存関係の監視は個々の行で行われるため、1 つの行をくすぐるだけで起動します。大規模な結果セットに対しては、やりたくないことかもしれません。

FormClosing イベントで、切断する前に各依存関係を起動します。

部分的なコード:

Private _dependency As SqlDependency = Nothing
Private _beingKilled = False

' dependency is set up in loadRecord(ByVal idRow as Integer)

Private Sub onDependencyChange(ByVal sender As Object, ByVal e As SqlNotificationEventArgs)
    ' This event may occur on a thread pool thread; It is illegal to update the UI from a worker thread.
    ' The following code checks to see if it is safe update the UI.
    Dim iSync As ISynchronizeInvoke = CType(_connection.masterForm, ISynchronizeInvoke)

    ' If InvokeRequired returns True, the code is executing on a worker thread.
    If iSync.InvokeRequired Then
        Dim tempDelegate As New OnChangeEventHandler(AddressOf onDependencyChange) ' Create a delegate to perform the thread switch
        Dim args() As Object = {sender, e}
        iSync.BeginInvoke(tempDelegate, args) ' Marshal the data from the worker thread to the UI thread.
    Else
        RemoveHandler _dependency.OnChange, AddressOf onDependencyChange
        If Not _beingKilled Then loadRecord(_id)
    End If
End Sub

次に、_beingKilled を True に設定し、何もしない更新を実行します。

于 2015-02-12T04:48:15.690 に答える