2012-03-01 5 views
2

私は、新しいASP.NET Web APIに基づいてWeb APIを作成しています。私は同時に複数のデータセットを提出する人々を扱う最良の方法を理解しようとしています。彼らが100,000のリクエストを持っているなら、彼らが一度に1,000を提出させることはいいでしょう。新しいASP.NET Web APIでは、「バッチ」リクエストをどのように設計するのですか?

はのは、私は私の連絡先コントローラに新しい連絡方法を作成しているとしましょう:

public string Put(Contact _contact) 
{ 
    //add new _contact to repository 
    repository.Add(_contact); 

    //return success 
} 

ユーザーが「バッチ」の新しい連絡先を提出することを可能にする適切な方法は何ですか?私は思っている:

public string BatchPut(IEnumerable<Contact> _contacts) 
{ 
    foreach (var contact in _contacts) 
    { 
     respository.Add(contact); 
    } 
} 

これは良い習慣ですか?これは連絡先のJSON配列でGETリクエストを解析しますか(正しく書式設定されていると仮定します)?

最後に、バッチリクエストに最も効果的に対応する方法に関するヒントを教えてください。 300人のうち4人が失敗したら?

ありがとうございます!

+0

要求サイズ、ユーザー数、ユーザーのタイプ、データの品質、時間制限、およびデータベースの信頼性に関する保証は、サーバー上にありますか?これらは、利用可能な設計選択に影響しますか? – bloudraak

+0

APIリクエストごとに1つのジョブを作成するAPIがあります。現時点では、APIは一度に1つのジョブしか取得していません。この制限は、200,000件もの要求を行う必要のある大規模なクライアントにとっては頭痛の種になっています。個々のAPI呼び出しはメッセージとしてAmazon SQSに入ります。したがって並行性は問題ではなく、大量の顧客にとっては頭痛の種です。ありがとう! –

+0

ビジネスプロセスで非同期処理が可能ですか?たとえば、私が保険会社で働いていたときに、引用符を計算するためにキューに入れていたので、クライアントがデータを提出し、見積もりが作成されたときにポーリングする必要がありました。利用可能なリソースに応じて、これには2〜2分から30分の時間がかかりました。 – bloudraak

答えて

2

コレクションをPUTするときは、コレクション全体を挿入するか、既存のコレクションを単一のリソースであるかのように置き換えます。これは、コレクションのGET、DELETE、POSTと非常によく似ています。これは原子操作です。 PUTへの個々の呼び出しを代用するのは、連絡先がRESTfullではないかもしれない(しかし、それは議論のために開かれている)。

HTTP pipeliningを見て、同じソケットのPutContact要求を複数送信することができます。リクエストごとに、そのリクエストに対する標準のHTTPステータスを返すことができます。

以前はSOAPでバッチ更新を実装していましたが、システムが負荷をかけているときに予想外の問題が発生しました。あなたが注意を払わなければ、同じ問題に遭遇するだろうと私は思っています。

  1. たとえば、データベースがバッチ更新の途中でタイムアウトすると、すべての地獄は故障の面で緩んで破った、信頼性などの取引と貧しいクライアントが実際に更新されたかを把握して試してみました再び。
  2. 更新するレコードが多すぎると、時間がかかりすぎてHTTPリクエストがタイムアウトする可能性があります。それはワームのもう一つの缶を開いた。
  3. 更新中にどれくらいのデータを受け入れるかという懸念もありました。 10MBの連絡先で十分でしたか?おそらく1MB?より大きいバッファは、メモリ使用量とセキュリティの面で多くの意味を持ちます。

私の提案はHTTP pipeliningです。

更新

私の提案は、非同期プロセスなどの連絡先の一括作成を処理するためだろう。 「仕事」は「バッチ作成」プロセスと同じであると仮定してください。

public class JobService 
{ 
    // Post 
    public void Create(CreateJobRequest job) 
    { 
     // 1. Create job in the database with status "pending" 
     // 2. Save job details to disk (or S3) 
     // 3. Submit the job to MSMQ (or SQS) 
     // 4. For 20 seconds, poll the database to see if the job completed 
     // 5. If the job completed, return 201 with a URI to "Get" method below 
     // 6. If not, return 202 (aka the request was accepted for processing, but has not completed) 
    } 

    // Get 
    public Job Get(string id) 
    { 
     // 1. Fetch the job from the database 
     // 2. Return the job if it exists or 404 
    } 
} 

キューからのものを消費し、バックグラウンド・プロセスは、データベースを更新または代わりに実行していて、完成にジョブのステータスを更新するサービスにPUTを実行することができますので、このサービスは、以下のように見えるかもしれません。

処理されたばかりのデータをナビゲートしたり、エラーに対処するためには別のサービスが必要です。

バックグラウンドプロセスでは、検証エラーを許容する必要があります。そうでない場合、またはサービスが検証を実行する場合(データベースの呼び出しなど、応答時間が保証されないと仮定した場合)、クライアントが問題を修正して要求を再送信するのに十分な情報を含むCreateJobResponseのような構造体を返すことができます。検証に時間がかかる場合は、バックグラウンド・プロセスで実行し、失敗したものとしてマークし、クライアントがエラーを修正して要求を再実行できるようにする情報でジョブを更新します。これは、クライアントがジョブが失敗したという事実を使って何かを行うことができることを前提としています。

ジョブの要求を多数の小さな「ジョブ」に分割すると、アトミックではない可能性があり、ジョブが正常に完了したかどうかを監視するためのさまざまな課題があります。

+0

こんにちはWerner - あなたの提案に感謝します。私はPUT動詞を使ってはいけません。私の間違いです。私はあなたがもう一度それを見る秒があれば、上記の質問を言い換えました。乾杯! –

+0

これは素晴らしいヴェルナーです。ありがとうございます!あなたは私がまだ答えたいと思っていない質問に答えています。私はMVC web apiのモデルバインディングが上記のようにカスタムオブジェクトのリストを処理するのに十分スマートであるかどうか不思議です。私はより大きな問題に対処するように思えます。乾杯! –

0

PUT操作はリソースを置き換えることになっています。通常、これは単一のリソースに対して行いますが、コレクションに対して行う場合、元のコレクションを渡された一連のデータで置き換えることになります。あなたがそれを行うことを意味しているかどうかは分かりませんが、コレクションのサブセットを更新していると仮定している場合は、PATCHメソッドがより適切な場合があります。

最後に、バッチリクエストに最も効果的に対応する方法についてのヒントを教えてください。 300人のうち4人が失敗したら?

これは本当にあなた次第です。あなたは200 OKか400 Bad Requestを送信し、その詳細を本文に入れることができるので、1つの応答しかありません。

+0

ありがとうモーリス - 私はPUTを言ってはいけません。私は人々が一度に1000のようなバッチで新しい連絡先を作成できるようにすることを目指しています。 –