New Relicの.NETエージェントには、エージェントバージョン6.0以降、非同期フレームワークインストルメンテーションが自動的に含まれています。.NET 4.5で導入された標準のasync-await
パターンでは、呼び出されたメソッドで実行されている作業がまだ進行中であっても、非同期メソッドの呼び出しが返される可能性があります。.NETエージェントは、この進行中の非同期作業を監視し、それが完了するのを待ってからタイミングを記録します。
非同期インストゥルメンテーションをサポートする機能
非同期のサポートが追加されたことにより、.NETエージェントで利用できる機能が増えました。しかし、この機能強化の一環として、これまでエージェントが提供していたいくつかの機能が利用できなくなりました。特記されている場合を除き、.NETエージェントでサポートされている他の フレームワーク の非同期メソッドをインストルメントすることはできません。
エージェントは、これらのHttpClient
非同期メソッドをインストルメントします。
SendAsync
GetAsync
PostAsync
PutAsync
DeleteAsync
GetStringAsync
GetStreamAsync
GetByteArrayAsync
エージェントは、これらのRestClient
非同期メソッドをインストルメントします。
ExecuteTaskAsync
ExecuteGetTaskAsync
ExecutePostTaskAsync
エージェントは、これらのSqlCommand
非同期メソッドをインストルメントします。
ExecuteReaderAsync
ExecuteNonQueryAsync
ExecuteScalarAsync
ExecuteXmlReaderAsync
エージェントは、これらのSqlDataReader
非同期メソッドをインストルメントします。
NextResultAsync
ReadAsync
エージェントはこれらのNpgsqlCommand
非同期メソッドをインストルメントします(Postgres):
ExecuteReaderAsync
ExecuteNonQueryAsync
ExecuteScalarAsync
.NETエージェントは、独自の非同期メソッドの カスタムインスツルメンテーションをサポートしています。
既知の制限
ここでは、当社の.NETエージェントを使用した非同期インスツルメンテーションに関する既知の制限事項をまとめています。
応答時間は、 async
- await
使用シーンで費やされた合計時間よりも短いと予想されます。Webエンドポイントの次のコード例を検討してください。
async Task<string> WebEndpointExample() { await DoSomethingForSomeSecondsAsync(5); //kick off a 5-second-work to be done. return "Complete";}
[Trace][MethodImpl(MethodImplOptions.NoInlining)]private static async Task DoSomethingForSomeSecondsAsync(int seconds){ await Task.Delay(TimeSpan.FromSeconds(seconds));}
このコード例では、 WebEndpointExample
が完了するまでに約5秒かかるため、 WebEndpointExample
エンドポイントへのリクエストを表すトランザクションの応答時間は約5秒になります。
エージェントは、トランザクションを構成する個々のセグメントの「ビジー」時間(インストルメントされたメソッドが実際に実行されている時間)もキャプチャします。それらはWebEndpointExample
とDoSomethingForSomeSecondsAsync
です。理想的には、2つのセグメントの合計実行時間は応答時間(約5秒)に等しくなります。
DoSomethingForSomeSecondsAsync
の実行時間は5秒であることが簡単にわかります。ただし、 WebEndpointExample
の実行時間は0秒に近い必要があります。(これは何の作業も行いません。 DoSomethingForSomeSecondsAsync
が完了するのはawait
秒です。)
ただし、エージェントは実行時間を約5秒と測定します。これは、メソッドが別のメソッドをawait
しているときに、エージェントがブロックされた時間(CPU時間ではない)を検出できないためです。したがって、合計時間は10秒として報告されます。これは、応答時間(約5秒)よりも長くなります。
同時に、エージェントはasync
メソッドの呼び出しが常に呼び出し元をブロックすることを想定できません。次の例はこれを示しています。
async Task<string> WebEndpointExample(){ var task = DoSomethingForSomeSecondsAsync(5); //kick off a 5-second-work to be done.
//Do something less than 5 seconds here.
await task; return "Complete";}
[Trace][MethodImpl(MethodImplOptions.NoInlining)]private static async Task DoSomethingForSomeSecondsAsync(int seconds){ await Task.Delay(TimeSpan.FromSeconds(seconds));}
この例では、応答時間はまだ約5秒ですが、 WebEndpointExample
の実際の実行時間は約0ではなくなりました。
レガシーASPパイプラインが存在する場合、.NETエージェントが非同期メソッドを計測しないという問題がありました。この問題は、.NET Framework 4.0以下で作成されたアプリケーションを.NET Framework 4.5以上に移行した場合にのみ発生しますが、非同期メソッドが導入される前にMicrosoft社がレガシーASPパイプラインを置き換えたため、この問題が発生します。
この問題がお客様のアプリケーションに影響するかどうか、また、影響する場合の解決方法については、 トラブルシューティングの手順を確認してください。
.NETエージェントは、 Task
またはTask<T>
以外の戻り型を持つ非同期メソッドのインストルメンテーションをサポートしていません。エージェントはasync void
メソッドをサポートしていません。
.NETエージェントは、 WCFアプリケーションを除いて、 begin*
およびend*
スタイルを使用する.NETメソッドをインストルメントしません。この例外を除いて、アプリケーションがこれらのタイプのメソッドを呼び出す場合、エージェントはそれらのセグメントを作成しません。ただし、残りのトランザクションとセグメントは正しく作成されます。
.NETエージェントは、スコープ付きのメトリクスや、アプリケーションが手動で作成したスレッド内のセグメントをキャプチャしません。
アプリケーションがインストルメント化された非同期メソッドを呼び出す場合は、 Task.Result()
などのTask
関連メソッドではなくawait
を使用して結果を待ちます。そうしないと、インストルメンテーションが正しく機能しない場合があります。
一般に、非同期メソッドを呼び出す場合は、 Task.Result()
の使用を避けてください。デッドロックが発生する可能性があります。
インストルメント化された非同期メソッドによって返されるpromiseに独自のContinueWith({})
ブロックを追加すると、インストルメンテーションによって報告されるタイミング測定に影響を与える可能性があります。たとえば、時間にはContinueWith
の実行にかかる時間が含まれる場合があります。
IIS ホストWCF サービスは、 WCFセグメントをExecuteRequestHandler
セグメントの下に適切にネストしません。 報告される合計時間は正確ですが、2 つのセグメントは trace 内では兄弟のように見えます。
トランザクショントレースのセグメントは、 transaction_tracer.stack_trace_threshold
より長く実行されている場合でも、スタックトレースを自動的に生成しません。