2013-02-15 12 views
7

私はMVC4 API REST新しいスレッドでプロセスを起動しようとしています。私はフレームワーク4.5で作業していて、同期を使用してクローラを待っています。MVC4 WebApiプロセスランチャ

私のコードは次のようになります。理想的には

[AcceptVerbs("POST")] 
public HttpResponseMessage Launch(string id) 
{ 
    runProcessAsync(id); // 1               

    return Request.CreateResponse(HttpStatusCode.Accepted); // 2 
} 

protected async void runProcessAsync(string id) 
{ 
    int exitcode = await runProcess(id); // 3 
    string exitcodesz = string.Format("exitcode: {0}", exitcode); // 4 
    // do more stuff with exitcode 
} 

protected Task<int> runProcess(string id) 
{ 
    var tcs = new TaskCompletionSource<int>(); 

    var process = new Process 
    { 
     StartInfo = { FileName = @"C:\a_very_slow_task.bat" }, 
      EnableRaisingEvents = true 
     }; 
     process.Exited += (sender, args) => tcs.SetResult(((Process)sender).ExitCode);    

     process.Start(); 

     return tcs.Task; 
    } 
} 

、誰かがAPIのREST呼び出しPOST動詞と(/タスク/ slowtask /起動)を行い、(受け入れ)202は非常に速く期待します。

Fiddler Web Debuggerを使用して、コードがLaunch(// 1)に入り、wait(// 3)に進み、低速タスクが作成されて開始され、Acceptedが返されます2)。しかし、この時点で、フィドラーは202の結果を示さない。遅いタスクが終了すると、コードがEXITCODE(// 4)を捕捉継続

http://imageshack.us/photo/my-images/703/fiddler1.png/

、次いで202はフィドラーに取り込まれる:添付された画像を見ます。

私はずっと前に戻りましたので、それは非常に奇妙です。私は何が欠けているのですか?非常に速く202を返すために、どのようにそのコードを変更して、タスクを忘れることができますか?

ノート:非フレームワーク4.5の機能でこれを行う方法は分かっていますが、私はasync/awaitの使い方を学びたいと考えています。

+1

これは、 'runProcessAsync()'が要求の同期コンテキストで実行されるためです。それを望まないなら、 'Task.Run(()=> runProcessAsync(id));'を使うことができます。しかし、IISはその時間中にあなたのappdomainをリサイクルできるので、 'runProcessAsync()'が完了しない可能性があるので、これに注意してください。 – svick

+0

私はそれをして動作します。あなたが私の問題を解決したので、適切な答えを入れなかったのは残念です。 – Jordi

答えて

4

これは、runProcessAsync()が要求の同期コンテキストで動作するためです。あなたがそれを望まないなら、Task.Run(() => runProcessAsync(id));を使うことができます。しかし、IISはその間にAppDomainをリサイクルできるので、この場合は注意してください。runProcessAsync()が完了しない可能性があります。

1

最も簡単な方法はrunProcessAsyncTaskに変更することです。可能であればasyncメソッドはTask/Task<T>を返し、にはがあるときにのみvoidを返すことを覚えておいてください。

ただし、これは非常に危険であることに注意する必要があります。 ASP.NETはHTTPサーバーなので、アクティブな要求がない場合は、必要に応じてAppDomainを自由に削除できます。これは、あなたの "exitcodeでより多くのことをする"が地球の顔からちょうど落ちることを意味します。

TaskをASP.NETランタイムに登録するために使用できるblog post with a BackgroundTaskManagerがあります。完了していないTaskが登録されていると、AppDomainのシャットダウンを遅らせようとします。しかし、それは単なる「ベストエフォート」です。そのようなことに対する保証はありません。アクティブな要求に関連付けられていないASP.NETで実行されているコードは危険です。

+0

私は理解できません。なぜ、タスクの戻り値の型を変更するのが助けになるのですか?同期コンテキストに問題がある場合は、何も変更されません。 – svick

関連する問題