NancyModuleGetメソッドを介して呼び出される長時間実行プロセスがあります。プロセスの実行中にブラウザーがハングするのではなく、この呼び出しを非同期にします。つまり、Getメソッドをすぐに返し、長時間実行されているプロセスにその処理を任せます。その後、定期的にプロセスのステータスを確認し、それに応じて行動することができました。
私はC#5の非同期/待機機能に不慣れですが、これらはまさにこの種のタスクのためのものであると確信しています。以下のコードは私の試みを示しています。期待どおりに非同期で実行されていないことを示すロギングをいくつか入れました。代わりに、長時間実行されるプロセスがGetメソッドをブロックするため、ブラウザーがハングします。
モジュール
public class TestModule : NancyModule
{
public TestModule(ITestService testService)
{
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
}
}
サービス
public interface ITestService
{
Task<bool> LongProcess();
}
public class TestService : ITestService
{
public async Task<bool> LongProcess()
{
await LongProcessAsynch();
return true;
}
private Task<bool> LongProcessAsynch()
{
Log.Write("LongProcess : Start");
Thread.Sleep(5000);
//Task.Delay(5000); <- Has same effect
Log.Write("LongProcess : Finish");
return true.AsTask();
}
}
拡張方法
public static Task<T> AsTask<T>(this T candidate)
{
var source = new TaskCompletionSource<T>();
source.SetResult(candidate);
return source.Task;
}
ログ出力
14/06/2012 19:22:29 : Module : Start
14/06/2012 19:22:29 : LongProcess : Start
14/06/2012 19:22:34 : LongProcess : Finish
14/06/2012 19:22:34 : Module : Finish
上記のログ出力から、LongProcess()
がGetモジュールの戻りをブロックしていることがわかります。タスクが非同期で実行されている場合、ログは次のようになります。
期待されるログ
Module : Start
LongProcess : Start
Module : Finish
LongProcess : Finish
await
実際に必要なのは、NancyModuleGetメソッドに入れることだと思います。以下のコードのようなものかもしれませんが、モジュールコンストラクターをとしてマークすることができず、Getメソッド内でasnyc
使用できないためawait
(または現在信じている) 、これを行うことはできません
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
await testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
ヘルプ、例、またはリソースへのポインタをありがとう。
編集1
async
さらなる調査により、asp.netはデフォルトで積極的に通話を阻止しているように見えることが明らかになっています。とは何か、Session
そしてそれが非UIスレッドを処理する方法と関係があると私は信じています。だから私は私のweb.configに以下を追加しました(以下を参照)
- UseTaskFriendlySynchronizationContext
- enableSessionState = "false"
残念ながら、それは何の違いもありません、そして、私のasync
/await
呼び出しLongProcess()
はまだブロックしています。
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
<add key="webPages:Enabled" value="false" />
</appSettings>
<system.web>
<httpRuntime targetFramework="4.5"/>
<pages controlRenderingCompatibilityVersion="4.0" enableSessionState="false" />
... more config
</configuration>