現在、このようなコードを使用して、SQL サーバー ジョブが実行されているかどうかを検出しています。(これは SQL Server 2005、すべての SP です)
return (select isnull(
(select top 1 CASE
WHEN current_execution_status = 4 THEN 0
ELSE 1
END
from openquery(devtestvm, 'EXEC msdb.dbo.sp_help_job')
where current_execution_status = 4 and
name = 'WQCheckQueueJob' + cast(@Index as varchar(10))
), 1)
)
そこに問題はなく、一般的に言えば、問題なく動作します。
しかし.... (常にしかし)
場合によっては、これを呼び出して「ジョブが実行されていません」という結果が返されたら、次の方法でジョブを開始しようとします。
exec msdb.dbo.sp_start_job @JobName
SQL は、「保留中の要求が既にあるため、SQLAgent はジョブの開始を拒否しました」と返します。
Ok。また、問題ありません。このコードがターゲット ジョブを開始する前に、ターゲット ジョブを開始できるわずかな時間枠があると考えられますが、開始されたかどうかを確認した後です。ただし、それを try catch にまとめて、エラーを無視することはできますよね?
begin try
if dbo.WQIsQueueJobActive(@index) = 0 begin
exec msdb.dbo.sp_start_job @JobName
break
end
end try begin catch
-- nothing here
end catch
ただし、ここに問題があります。
10回中9回、これはうまくいきます。SQL エージェントはエラーを発生させ、キャッチされ、処理が続行されます。ジョブは既に実行されているため、問題はありません。
しかし、時折、[ジョブ履歴] ビューにメッセージが表示されることがあります (特定のジョブが実行されているかどうかを検出し、実際に別のジョブから実行されていない場合は開始する上記のコードを覚えておいてください)。保留中のリクエストがすでにあるため、ジョブの開始を拒否しました。」
もちろん、これは TRY CATCH が処理するはずの正確なエラーです!
これが発生すると、実行中のジョブはただ停止しますが、私が知る限り、すぐには終了しません。あちこちにログを記録しましたが、一貫性がありません。一度失敗すると、場所 a になり、次は場所 b になります。場合によっては、場所 A と場所 B には、
select @var = 'message'
それらの間に。非常に奇妙な。基本的に、ジョブは不用意にダンプされたように見え、ジョブで実行するために残っているものは +まったく実行されません。
ただし、「exec StartJob」を削除すると (または、ターゲット ジョブがまだ実行されていないことがわかっているときに 1 回だけ呼び出すと)、すべてが完全に機能し、ジョブ内のすべての処理が実行されます。
このすべての背後にある目的は、(特に) トリガーの結果としてジョブを開始することであり、ジョブが既に開始されている場合は、実際に「もう一度開始する」必要はありません。
SQL エージェントのジョブ処理でこのような動作に遭遇した人はいますか?
編集:現在の制御の流れは次のようになります。
- テーブルへの変更 (更新または挿入)...
- 呼び出すトリガーを起動します...
- ...を呼び出すストアドプロシージャ
- sp_Start_Job...
- 特定のジョブを開始します...
- 別のストアド プロシージャ (CheckQueue と呼ばれる) を呼び出します...
- いくつかの処理を実行し、...
- いくつかのテーブルをチェックし、その内容によっては...
- 別のジョブで sp_start_job を呼び出して、追加の作業を処理する 2 番目の同時ジョブを開始します (この 2 番目のジョブは CheckQueue sproc も呼び出しますが、2 つの呼び出しは完全に別個のデータ セットで動作します)。