注
これは、スケーラブルなカスタマイズ設計に関する一連のトピックの 2 番目です。 最初に、「 Microsoft Dataverse のスケーラブルなカスタマイズ設計」を参照してください。
ここで直面する多くの課題の背後にある最も基本的な概念の 1 つは、データベース トランザクションの概念です。 Dataverse では、データベースはシステムに対するほぼすべての要求の中心にあり、場所データの整合性が主に適用されます。
- 内部またはコードのカスタマイズの一部である Dataverse データ操作は、完全に分離して機能しません。
- すべての Dataverse データ操作は、データ レベルまたはプロセッサ、メモリ、I/O 使用率などのインフラストラクチャ レベルで、同じデータベース リソースと対話します。
- 競合する変更から保護するために、各要求は、表示または変更されるリソースに対するロックを受け取ります。
- これらのロックはトランザクション内で取得され、トランザクションがコミットまたは中止されるまで解放されません。
トランザクションとロックの認識
この領域で問題が発生する可能性がある一般的な理由は、カスタマイズがトランザクションに与える影響を認識できないからです。
この方法の詳細はこの記事の範囲外ですが、考慮すべき最も簡単な要素は、Dataverse がデータベース内のデータと対話する場合です。 SQL Server は、次のようなデータに対するトランザクションによって実行される適切なロックを決定します。
- レコードを作成すると、そのレコードに対して書き込みロックが生成されます。
- レコードを更新すると、レコードに対して書き込みロックが行われます。
- テーブルまたはレコードに対してロックが行われると、対応するインデックス レコードにもロックが設定されます。
ただし、これらのロックのスコープと期間に影響を与えることは可能です。 また、特定のシナリオでロックが不要であることを SQL Server に示すこともできます。
SQL Server データベースのロックと、同じデータにアクセスしようとする個別の要求の影響について考えてみましょう。 次の例では、アカウントを作成すると、プロセスが設定されます。いくつかのプロセスでは、レコードが作成されるとすぐにトリガーされるプラグインが含まれており、いくつかは作成時に開始される関連する非同期ワークフローに含まれています。
この例では、アカウント更新プロセスに複雑な後処理がある場合に、他のアクティビティも同じアカウントレコードと対話する場合の結果を示します。 アカウント更新トランザクションの進行中に非同期ワークフローが処理された場合、このワークフローは、同じアカウント レコードを変更するための更新ロックの取得を待機してブロックされる可能性があります。このワークフローはまだロックされています。
トランザクションは、プラットフォームに対する特定の要求の有効期間内にのみ保持されることに注意してください。 ロックは、ユーザー セッション レベルでは保持されず、ユーザー インターフェイスに情報が表示されている間も保持されません。 プラットフォームは要求を完了するとすぐに、データベース接続、関連トランザクション、および実行されたロックを解放します。
ブロッキング
前の例のブロックの種類自体は不便な場合もありますが、Dataverse が何百もの同時実行アクションを処理できるプラットフォームであると考えると、このブロックはより深刻な結果につながる可能性もあります。 個々のアカウント レコードのロックを保持すると、影響が合理的に制限される可能性がある一方で、リソースの競争が激しい場合はどうなりますか。
たとえば、各アカウントに一意の参照番号が与えられると、使用されている参照番号を追跡する単一のリソースが、すべてのアカウント作成プロセスによってブロックされる可能性があります。 自動番号付け例で説明したように、多数のアカウントが並列に生成される場合、重複する要求はすべて、その自動番号付けリソースにアクセスし、アクションが完了するまでブロックする必要があります。 各アカウント作成プロセスにかかる時間が長くなり、同時要求が多いほど、ブロックが多くなります。
自動番号リソース ロックを取得する最初の要求は簡単に完了できますが、2 番目の要求は最初の要求が完了するのを待ってから、次の一意の参照番号が何であるかを確認する必要があります。 3 番目の要求は、最初の要求と 2 番目の要求の両方が完了するまで待機する必要があります。 要求が多いほど、ブロックが長くなります。 要求が十分に存在し、各要求に十分な時間がかかる場合、この遅延により、個々に正常に完了する場合でも、後の要求がタイムアウトになる可能性があります。
ロック解除
ロックが解放されず、トランザクションが完了するまで保持される主な理由は 2 つあります。
- トランザクションが後でデータ項目を更新する別の要求を行った場合、データベース サーバーは一貫性を確保するためにロックを保持します。
- また、データベース サーバーでは、後で発行されたエラーまたは中止コマンドによってトランザクション全体がロールバックされる可能性があるため、一貫性を確保するために、トランザクションの有効期間全体にわたってロックを保持する必要があります。
プロセスが特定のデータとの対話を完了した場合でも、トランザクション全体が完了してコミットされるまでロックが保持されることを認識することが重要です。 トランザクションが長いほどロックが長くなり、他のスレッドがそのデータと対話できなくなります。 後で示すように、これには、同じトランザクション内で動作し、同期ワークフローなどのトランザクションの有効期間を大幅に延長できる関連するカスタマイズも含まれます。
次の例では、アカウントの作成前プラグインのカスタム エンティティに対する書き込みロックは、アカウントの作成に関連付けられているすべてのロジックが完了するまでロックされます。
断続的なエラー: タイミング
断続的な動作は、同時アクティビティからのブロックの明らかな症状です。 以前に失敗したときに後でまったく同じアクションを繰り返すと、エラーまたは低速が同時に発生した他の原因である可能性が高くなります。
多くの場合、問題のデバッグには問題のある機能を最小限に戻すことが含まれるので、これを実現することが重要です。 ただし、問題が断続的にしか発生しない場合は、失敗したアクションがシステム内の別のアクティビティと競合している場所を調べる必要があり、潜在的な競合ポイントを確認する必要があります。 個々のプロセスを最適化することで、競合を軽減できます。ただし、処理時間が短いほど、アクティビティが他のプロセスと競合する可能性は低くなります。
トランザクション制御
ほとんどの場合、トランザクションの使用方法はプラットフォームに任せる可能性がありますが、必要なロジックが十分に複雑で、目的の結果を得るためにトランザクションに対する理解と影響が必要になるシナリオがあります。 Dataverse には、トランザクションの使用方法に異なる影響を与えるさまざまなカスタマイズ アプローチが用意されています。
各種類のカスタマイズがプラットフォーム トランザクションにどのように関与するかを理解したら、Dataverse で複雑なシナリオを効果的にモデル化し、その動作を予測できます。
前述のように、トランザクションはプラットフォームへの要求の有効期間中にのみ保持され、プラットフォームステップが完了した後に維持されるものではありません。 この期間が限られていると、外部クライアントによって長期間トランザクションが保持され、他のプラットフォーム アクティビティがブロックされるのを回避できます。
プラットフォームのジョブは、プラットフォーム トランザクション パイプライン全体の一貫性を維持し、必要に応じてカスタマイズがその同じトランザクションに参加できるようにすることです。
モデル駆動型アプリでトランザクションを使用する方法
カスタマイズがプラットフォームとどのように対話するかを理解する前に、モデル駆動型アプリがプラットフォームへの要求を使用する方法と、それがトランザクションの使用にどのように影響するかを理解すると便利です。
| Operation | Description |
|---|---|
| フォーム (取得) | • 他の用途への影響が少ない。 |
| Create | • プラットフォームを介して作成要求を実行します。 • 新規レコードには他にブロックするものは何もないため、他の活動への影響は小さい。 • 完了までテーブル全体に対するロック クエリをブロックする可能性があります。 • 多くの場合、影響を与える可能性のあるカスタマイズで関連するアクションをトリガーできます。 |
| Update | • プラットフォームを介して更新要求を実行します。 • 競合が発生する可能性が高くなります。 更新ロックは、そのレコードを更新する他の何かをブロックします。 • 多くの場合、他のアクティビティをトリガーします。 • まれに、更新ロックによって読み取りロックがブロックされる場合があります。 これが発生する可能性がある例の 1 つは、Dataverse メタデータが変更されている場合です。Dataverse メタデータ変更トランザクションによって実行された読み取りは、更新ロックによってブロックされます。 |
| ビュー (複数のデータを取得) | • 他の用途への影響が少ない。 • クエリのパフォーマンスが低下すると、データベースのリソースが過剰になり、タイムアウトが発生する可能性があります。 |
イベント パイプライン: プラットフォーム ステップ
イベント パイプラインが開始されると、プラットフォーム ステップを含む SQL トランザクションが作成されます。 これにより、プラットフォームによって実行されるすべてのデータベース アクティビティが一貫して処理されます。 トランザクションはイベント パイプラインの開始時に作成され、処理が正常に完了したかどうかに応じて、コミットまたは中止されます。
カスタマイズ要求
カスタマイズ内でプラットフォームによって開始されるトランザクションに参加することもできます。 カスタマイズの種類ごとに異なる方法でトランザクションに参加します。 以降のセクションでは、それぞれについて順番に説明します。
- 同期プラグイン (事前または事後操作: トランザクション コンテキスト)
- 同期プラグイン (事前操作と事後操作: トランザクション コンテキスト内)
- 同期プラグイン (PreValidation: トランザクション コンテキスト外)
- 同期プラグイン (PreValidation: トランザクション コンテキスト内)
- 非同期プラグイン
- プラグイン トランザクションの使用の概要
- 同期ワークフロー
- 非同期ワークフロー
- カスタム ワークフロー アクティビティ
- カスタム アクション
- Web サービス要求
同期プラグイン (事前操作または事後操作: トランザクションのコンテキスト)
プラグインがイベントに登録されている場合は、トランザクション内の PreOperation または PostOperation ステージに対して登録できます。 プラグインからのメッセージ要求はすべて、トランザクション内で実行されます。 つまり、トランザクションの有効期間と、取得されたすべてのロックが拡張されます。
同期プラグイン (事前操作と事後操作: トランザクション コンテキスト内)
プラグインは、 PreOperation ステージと PostOperation ステージの両方に対して登録できます。 この場合、 PreOperation プラグインの開始から PostOperation プラグインが完了するまで、トランザクションがさらに拡張される可能性があります。
同期プラグイン (PreValidation: トランザクション コンテキスト外)
プラグインは、 PreValidation ステージに登録することで、プラットフォーム トランザクションの外部で動作するように登録することもできます。
注
独自のトランザクションは作成されません。 その結果、プラグイン内の各メッセージ要求は、データベース内で個別に処理されます。
このシナリオは、パイプライン イベントの最初のステージとして PreValidation が呼び出された場合にのみ適用されます。 プラグインは PreValidation ステージに登録されていますが、次のセクションで説明するようにトランザクションに参加する可能性があります。 PreValidation プラグインがトランザクションに参加していないと見なすことはできませんが、その場合は実行コンテキストから確認できます。
同期プラグイン (PreValidation: トランザクション コンテキスト内)
関連するシナリオは、 PreValidation プラグインが登録されていても、関連するパイプライン イベントが既存のトランザクション内からのメッセージ要求によってトリガーされる場合に発生します。
次の図に示すように、アカウントを作成すると、初回作成時に PreValidation プラグインがトランザクションの外部で最初に実行される可能性があります。 ポスト プラグインの一部として、2 つ目のイベント パイプラインが親パイプライン内から開始されるため、関連する子アカウントを作成するためのメッセージ要求が行われると、同じトランザクションに参加します。
その場合、 PreValidation プラグインはトランザクションが既に存在することを検出し、 PreValidation ステージに登録されていてもそのトランザクションに参加します。
前述のように、プラグインは、 IsInTransaction プロパティの実行コンテキストを確認できます。このプロパティは、このプラグインがトランザクション内で実行されているかどうかを示します。
非同期プラグイン
プラグインは、非同期的に動作するように登録することもできます。 この場合、プラグインはプラットフォーム トランザクションの外部でも機能します。
注
プラグインは独自のトランザクションを作成しません。プラグイン内の各メッセージ要求は、個別に処理されます。
プラグイン トランザクションの使用の概要
まとめると次のようになります。
- 同期プラグインは通常、トランザクションに参加します。
- 非同期プラグインはプラットフォーム トランザクションに参加しません。各要求は個別に実行されます。
- PreValidation プラグインはトランザクションを作成しませんが、トランザクションが既に存在する場合は参加します。
| Event | ステージ名 | トランザクションがまだ存在しない | トランザクションが既に存在する |
|---|---|---|---|
| イベント前 | PreValidation | トランザクションは作成されません。 トランザクションに参加しません。各要求は、データベースに対して独立したトランザクションを使用します | 既存のトランザクションに参加する |
| イベント前 | PreOperation | 既存のトランザクションに参加する | 既存のトランザクションに参加する |
| 事後イベント | PostOperation | 既存のトランザクションに参加する | 既存のトランザクションに参加する |
| 非同期 | N/A | トランザクションは作成されません。 トランザクションに参加しません。各要求は、データベースに対して独立したトランザクションを使用します | N/A |
同期ワークフロー
トランザクションの観点から見ると、同期ワークフローは操作前/事後プラグインとして機能します。そのため、これらはプラットフォーム パイプライン トランザクション内で動作し、トランザクション全体の長さに同じ影響を与える可能性があります。
非同期ワークフロー
非同期ワークフローは、プラットフォーム トランザクションの外部でトリガーされます。
注
また、ワークフローは独自のトランザクションを作成しないため、ワークフロー内の各メッセージ要求は個別に処理されます。
次の図は、プラットフォーム トランザクションの外部で動作する非同期ワークフローと、独自の独立したトランザクションを開始する各ステップを示しています。
カスタム ワークフロー アクティビティ
カスタム ワークフロー アクティビティは、親ワークフロー コンテキスト内で動作します。
- 同期ワークフロー: トランザクション内で動作する
- 非同期ワークフロー: トランザクションの外部で動作する
次の図は、最初に同期ワークフロー内で動作し、次に非同期ワークフロー内で動作するカスタム アクティビティを示しています。
カスタム アクション
カスタム アクションは、独自のトランザクションを作成できます。 これは重要な機能です。 カスタム アクションは、ロールバックを有効にするように構成されているかどうかに応じて、プラットフォーム ステップの外部で個別のトランザクションを作成できます。
- ロールバック セットを有効にする
- トランザクション内で実行されているプラグインからメッセージ要求を介して呼び出され、[ロールバックの有効化] が設定されている場合、カスタム アクションは既存のトランザクション内で動作します。
- それ以外の場合、カスタム アクションは新しいトランザクションを作成し、その中で実行します。
- ロールバックの設定が未設定
- カスタム アクションは、トランザクション内では動作しません。
Web サービス要求
Web サービスを介して外部から要求が行われると、パイプラインが作成され、前に説明したようにパイプライン内のトランザクション処理が行われますが、応答が返されるとトランザクションは維持されません。 次の要求が不明になるまでの期間はどのくらいであるため、プラットフォームでは、他のアクティビティをブロックするリソースのロックは許可されません。
同じ実行コンテキストを使用してプラグイン内で複数の要求が行われる場合、トランザクション参照を維持する共通の実行コンテキストであり、同期プラグインでは、各要求が同じトランザクション内で確実に行われます。 要求間で実行コンテキストを維持する機能はプラグインの外部では使用できないため、外部で行われた個別の要求間でトランザクションを維持することはできません。
1 つの Web サービス要求の一部として複数のアクションを Dataverse プラットフォームに渡すことができる特別なメッセージが 2 つあります。
| メッセージ | Description |
|---|---|
ExecuteMultiple |
これにより、同じ Web サービス要求内で複数の独立したアクションを渡すことができます。 これらの各要求はプラットフォーム内で個別に実行されるため、要求間でトランザクション コンテキストが保持されません。 |
ExecuteTransaction |
これにより、同期プラグイン内から行われた複数のメッセージ要求と同様の方法で、同じデータベース トランザクション内で複数のアクションを処理できます。 この機能は、複数のメッセージ要求と同様の影響を及ぼします。つまり、各アクションに時間がかかる場合 (コストの高いクエリを実行したり、関連する同期プラグインやワークフローの長いチェーンをトリガーしたりするなど) と、より広範なプラットフォームで問題がブロックされる可能性があります。 |
プラグイン内でのWeb API (OData) 要求
プラグインと同じ組織に対して、プラグイン内で Web API (OData) 要求を使用しないでください。 常に IOrganizationService メソッドを使用します。 これにより、操作がパイプライン トランザクションに参加できるように、トランザクション コンテキストを渡すことができます。
次のステップ
データベース トランザクションに加えて、複数の同時データ操作がシステムに与える影響を理解することが重要です。 詳細情報: スケーラブルなカスタマイズ設計: コンカレンシーの問題