2016-09-05 4 views
0

Quartz.netを使用してメッセージキューにメッセージを送信するスケジュールされたジョブを開発しています。 IJobのExecuteメソッドは非同期ではありません。だから私は非同期タスクを使用することはできません...しかし、私はawaitキーワードでメソッドを呼び出すしたい。私のコードを見てください。私が正しいことをしているかどうかは分かりません。誰もがこれで私を助けてくれる?C#メソッドを非同期メソッドを変更せずにawaitキーワードを使用する方法

private async Task PublishToQueue(ChangeDetected changeDetected) 
{ 
    _logProvider.Info("Publish to Queue started"); 

    try 
    { 
     await _busControl.Publish(changeDetected); 

     _logProvider.Info($"ChangeDetected message published to RabbitMq. Message"); 
    } 
    catch (Exception ex) 
    { 
     _logProvider.Error("Error publishing message to queue: ", ex); 

     throw; 
    } 
} 

public class ChangedNotificatonJob : IJob 
{ 
    public void Execute(IJobExecutionContext context) 
    { 
        //Publish message to queue 
        Policy 
         .Handle<Exception>() 
         .RetryAsync(3, (exception, count) => 
         { 
          //Do something for each retry 
         }) 
         .ExecuteAsync(async() => 
         { 
          await PublishToQueue(message); 
         }); 
    } 
} 

これは正しい方法ですか?私は.GetAwaiter()を使用しました。

Policy 
     .Handle<Exception>() 
     .RetryAsync(_configReader.RetryLimit, (exception, count) => 
     { 
      //Do something for each retry 
     }) 
     .ExecuteAsync(async() => 
     { 
      await PublishToQueue(message); 
     }).GetAwaiter() 

おかげ

+0

[C#で同期メソッドから非同期メソッドを呼び出す方法は?](http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in- c) – smoksnes

答えて

1

ポリーの.ExecuteAsync()戻りTaskTaskの場合は、.Wait()(または他のブロッキングメソッド)を呼び出して、完了するまで同期的にブロックするか、例外をスローすることができます。そうでなければ成功-や出版のタスクに同期し遮断するしかないので、あなたが発見したい場合は、awaitを使用することはできません

IJob.Execute(...)asyncないので、あなたが、観察してきたように、前IJob.Execute(...)が返されます。

.Wait()は、タスクの例外を再スローさせ、AggregateExceptionにラップします。これは、すべてのポリオーケストレーションによる再試行が失敗した場合に発生します。

あなたは、その例外をどうするかを決定する必要があります:

  • あなたは、呼び出し元が、それを扱うことを再スローまたはそれをキャッチし、それがクォーツジョブ外でカスケードせてはいけないしたい場合。

  • IJob.Execute(...)から返信する前に処理したい場合は、の全体が.ExecuteAsync(...).Wait()になる必要があります。 Pollyの.ExecuteAndCaptureAsync(...)構文を考えてみましょう。つまり、実行の最終結果をPolicyResultインスタンスに置き換えて、その外部try-catchを提供する必要がなくなります。 Polly docoを参照してください。


あり、あなたの唯一の意図は、メッセージの発行が失敗したことをどこかにログインすることであればさらなる代替があり、あなたはそのログがIJob.Execute(...)リターンか前に起こるかどうかを気にしません。その場合、.Wait()を使用する代わりに、.ContinueWith(...)を使用してExecuteAsync()に継続タスクを連鎖させ、そこにログインすることができます。私たちはこのアプローチを採用し、失敗したメッセージの公開を特別な「メッセージ病院」にキャプチャします。十分な情報をキャプチャして、必要に応じて後でそのメッセージを再度公開するかどうかを選択できます。このアプローチが価値あるものかどうかは、決してメッセージを失わないことがいかに重要かにかかっています。


編集:GetAwaiter()は無関係です。これは、を非asyncメソッドの中で使用することを魔法のようには開始しません。

+0

http://www.quartz-scheduler.net/2016/08/16/quartznet-3.0-alpha1-released.htmlを参照してください。石英。v3リリースで 'async' /' await'サポートを追加するネットプラン(現在はNuGetのプレビュー中)。おそらく、それはあなたに 'IJobAsync'または' IAsyncJob'インターフェースまたは同様のものを与えるはずです。それは書面の時に[文書化されていません](http://quartznet.sourceforge.net/apidoc/3.0/html/)です。 –

+1

'GetAwaiter()。GetResult()'は、 'AggregateException'ラッパーを避けるため、Wait()の代わりになります。 –

+0

@StephenCleary素敵な洞察力 - ありがとう。 –

関連する問題