10

現在、このようなコードを使用して、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 エージェントのジョブ処理でこのような動作に遭遇した人はいますか?

編集:現在の制御の流れは次のようになります。

  1. テーブルへの変更 (更新または挿入)...
  2. 呼び出すトリガーを起動します...
  3. ...を呼び出すストアドプロシージャ
  4. sp_Start_Job...
  5. 特定のジョブを開始します...
  6. 別のストアド プロシージャ (CheckQueue と呼ばれる) を呼び出します...
  7. いくつかの処理を実行し、...
  8. いくつかのテーブルをチェックし、その内容によっては...
  9. 別のジョブで sp_start_job を呼び出して、追加の作業を処理する 2 番目の同時ジョブを開始します (この 2 番目のジョブは CheckQueue sproc も呼び出しますが、2 つの呼び出しは完全に別個のデータ セットで動作します)。
4

3 に答える 3

4

まず、サービスブローカーを見る機会がありましたか?あなたの説明から、それはあなたが実際に望んでいるもののように聞こえます。

違いは、ジョブを開始する代わりに、データをSBキューに入れ、SBが処理プロシージャを非同期で呼び出し、すでに実行中のジョブなどの問題を完全に回避します。追加のスレッドを自動生成/終了し、要求が指示します、注文等のお世話になります。

これは良い(そして漠然と関連した)チュートリアルです。http://www.sqlteam.com/article/centralized-asynchronous-auditing-with-service-broker

なんらかの理由でSBを使用できないと仮定しましょう(しかし、真剣にそうしてください!)。

ジョブspidのcontext_infoを使用するのはどうですか。

  1. ジョブは、各ステップを個別に実行するラッパーprocを呼び出します。
  2. ラッパープロシージャ内の最初のステートメントは

    DECLARE @context_info VARBINARY(30)
    SET @context_info = CAST('MyJob1' AS VARBINARY)
    SET CONTEXT_INFO @context_info
    
  3. procが終了したとき(またはcatchブロック内)

    SET CONTEXT_INFO 0x0
    
  4. あなたがあなたの仕事を呼ぶことを考えているとき、これをしてください:

    IF NOT EXISTS (SELECT * FROM master..sysprocesses WITH (NOLOCK) WHERE context_info=CAST('MyJob1' AS VARBINARY))
        EXEC StartJob
    

ラッパープロシージャが終了するか、接続が閉じられると、context_infoは消えます。

グローバル一時テーブル(つまり、## JobStatus)を使用することもできます。これらは、それを参照するすべてのspidが切断されるか、明示的に削除されると消えます。

ほんの少しの考え。

于 2011-08-03T17:35:25.453 に答える
3

実行中のジョブを提供するクエリがあります。おそらくそれが役立つでしょう。それは私のために働いていますが、何か問題を見つけた場合はお知らせください。修正を試みます。乾杯。

-- get the running jobs
--marcelo miorelli
-- 10-dec-2013


SELECT sj.name
      ,DATEDIFF(SECOND,aj.start_execution_date,GetDate()) AS Seconds
 FROM msdb..sysjobactivity aj
 JOIN msdb..sysjobs sj on sj.job_id = aj.job_id
WHERE aj.stop_execution_date IS NULL -- job hasn't stopped running
 AND aj.start_execution_date IS NOT NULL -- job is currently running
--AND sj.name = 'JobName'
and not exists( -- make sure this is the most recent run
    select 1
    from msdb..sysjobactivity new
    where new.job_id = aj.job_id
      and new.start_execution_date > aj.start_execution_date )
于 2014-09-27T14:52:31.437 に答える
-3

すでに実行中のジョブに対処するには: 1. タスク マネージャーを開きます 2. ImageName "DTExec.exe" のプロセスが実行されているかどうかを確認します 3. プロセスが実行中で、問題のあるジョブである場合は、"プロセスの終了" を実行します。

于 2013-07-10T11:16:17.610 に答える