2017-09-17 5 views
0

私はこのシナリオを持っており、私の会社のすべてのワークステーションに通知メッセージを送信する必要があるところで作業しています。私たちはデスクトップ通知を処理するクライアントサービスを持っています。これは非常に簡単なWebApiです。Asynch and Parallel HttpClient 62,000台以上のマシンへのリクエスト:ベストプラクティスリクエスト

質問/要件 どうすれば両方の非同期と並行して、サーバ/ ASP.NetのWebアプリからのすべてのこれらのマシンにリクエストを送信し、カスタムログファイルへの応答をキャプチャするのですか?

通知が送信されたときに、多くのコンピュータがオフになっている可能性があります。または、マシンが廃止された可能性があるため、DNSが解決できないことがあります。

現在プロトタイプされているコードに対するリクエスト/応答サイクルは、非ブロッキングのものである必要があります。ユーザーがこれらすべてのマシンからの応答を待つ必要はありません。

宿題: 私は非同期操作を理解するにはIOバインド操作に適しています、マシンのしかし数は、私はより良い、このような状況に合うかもしれませんが、一緒に並列と非同期 感じさせるように多くのです。私はfalseに処分オプション付きのコンストラクタでServicePointManager.DefaultConnectionLimit = 10000

のHttpClientを設定している

が渡されました。以下のコード - ファクトリクラスを参照してください。

フレームワークのHttpClientクラスは再利用のために設計されていますが、基本アドレスのように一部のプロパティが変更されないことを理解しています。出典:HttpClient - This instance has already started

私は、要求/応答固有ID(相関ID)を使用して、すべての非同期操作と並列操作を特定の要求に対して同じフォルダに確実に適用します。

TaskCanceledException catchブロックがヒットすることはありません!

タイムアウトが30秒に延長されましたが、これは十分以上のものです。

プロトタイプコード:

public class HttpClientFactory : IHttpClientFactory 
    { 
     public void CreateClient(string baseUrl, Action<HttpClient> methodToExecute) 
     { 
      using (var handler = new HttpClientHandler()) 
      { 
       handler.AllowAutoRedirect = true; 
       using (var client = new HttpClient(handler, false)) 
       { 
        client.BaseAddress = new Uri(baseUrl); 
        client.Timeout = TimeSpan.FromSeconds(30); 
        methodToExecute(client); 
       } 
      } 
     } 
    } 

IHttpClientFactoryが一時的である(IOC)プロトタイプコードで

workstationUrls.ForEach(baseUrl => 
      { 
       _httpClientFactory.CreateClient(baseUrl, async (client) => 
       { 
        await client.PostAsync(resourceUrl, content).ContinueWith(t => 
        { 
         try 
         { 
          var response = t.Result; 

          var workstationResponse = new WorkstationResponse 
          { 
           StatusCode = (int)response.StatusCode, 
           Response = response.Content.ReadAsStringAsync().Result 
          }; 

          workstationResponse.IsSuccess 
           = workstationResponse.StatusCode >= 200 && 
            workstationResponse.StatusCode <= 299 
            ? true 
            : false; 

          var docContent = JsonConvert.SerializeObject(workstationResponse); 
          if (workstationResponse.IsSuccess) 
          { 
           // Write workstation log 
           File.WriteAllText(path 
                + "\\Bulk Notifications\\" 
                + userFolder + "\\Success\\" 
                + GetWorkstationNameFromUrl(baseUrl) 
                + GetUniqueTimeStampForFileNames() 
                + workstationResponse.IsSuccess + ".txt", 
            docContent); 
          } 
          else 
          { 
           // Write workstation log 
           File.WriteAllText(path 
                + "\\Bulk Notifications\\" 
                + userFolder + "\\Fail\\" 
                + GetWorkstationNameFromUrl(baseUrl) 
                + GetUniqueTimeStampForFileNames() 
                + workstationResponse.IsSuccess + ".txt", 
            docContent); 
          } 

         } 
         catch (TaskCanceledException exe) 
         { 

         } 
         catch (Exception ex) 
         { 

          var workstationResponse = new WorkstationResponse 
          { 
           Exception = ex, 
           IsSuccess = false 
          }; 
          var docContent = JsonConvert.SerializeObject(workstationResponse); 
          // Write workstation log 
          File.WriteAllText(path 
               + "\\Bulk Notifications\\" 
               + userFolder + "\\Fail\\" 
               + GetWorkstationNameFromUrl(baseUrl) + " " 
               + GetUniqueTimeStampForFileNames() + " " 
               + workstationResponse.IsSuccess + ".txt", docContent); 
         } 
        }); 
       }); 
      }); 

問題: 私は例外メッセージにこれらのエラーを取得し、スタックトレースには思えません役に立った

  • 「に配置されたobject.Object名にアクセスすることはできません: 『System.Net.Http.StringContent』」
  • 「タスクがキャンセルされた」
+0

アクション 'Action methodToExecute'をTaskを返すfuncに変更することから、' HttpClient'と適切に対話する非同期メソッドを待つことができます。これにより、例外が発生します。 –

+0

Thans Peter、違いがあるかどうか試してみましょう。 – RaM

答えて

3

、まず非同期並列は相互に排他的ではありません。その違いは、使用するコンストラクトにあります。また、「従来の」並列処理とは異なり、非同期操作ごとにスレッドを消費/ブロックしているわけではありません。

非同期操作を同時に実行し、それらのすべてが完了するのを待っている(非同期的に)ための最も基本的な構成はTask.WhenAllです。私は単一ワークステーションにメッセージを送信するための非同期メソッドを定義することから始めたい:(。実装は、あなたのコードからかなり簡単に導くことができる)

async Task SendMessageToWorkstationAsync(string url) 

を次に、このようにそれを呼び出します。

await Task.WhenAll(workstationUrls.Select(SendMessageToWorkstationAsync)); 

あなたがBaseAddressを設定しているので、あなたは、単一のインスタンスを再利用していない場合は第二には、HttpClientについては、解決策は単純です:それをしないでください。 :)必須ではありません。ファクトリクラスをスキップし、代わりに単一の共有HttpClientインスタンスを作成し、各要求に完全なURIを指定します。

最後に、さまざまな要因によっては、62,000以上の同時リクエストがシステムが処理できる以上のものがあることがわかります。そのような場合は、あなたの並列性を抑制したいでしょう。私はそれを行うための最善の方法がTPL Dataflowであることを発見しました。それを行う方法の詳細については、this questionを参照してください。

+0

洞察のために、toddに感謝します。私が何か進歩を遂げることができるかどうか試してみましょう。 – RaM

関連する問題