での競合の検出と解決 AWS AppSync - AWS AppSync

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

での競合の検出と解決 AWS AppSync

で同時書き込みが発生した場合は AWS AppSync、更新を適切に処理するように競合検出および競合解決戦略を設定できます。競合の検出では、ミューテーションがデータソースに実際に書き込まれた項目と競合しているかどうかが判断されます。競合検出は、 SyncConfig conflictDetectionフィールドの の値を に設定することで有効になりますVERSION

競合の解決は、競合が検出された場合に実行されるアクションです。これは、 の競合ハンドラーフィールドを設定することによって決定されます SyncConfig。次の 3 つの競合の解決戦略があります。

  • OPTIMISTIC_CONCURRENCY

  • AUTOMERGE

  • LAMBDA

バージョンは書き込みオペレーション AWS AppSync 中に によって自動的に増分されるため、クライアントやバージョン対応のデータソースで設定されたリゾルバーの外部では変更しないでください。変更すると、システムの整合性動作が変更され、データが失われる可能性があります。

オプティミスティック同時実行数

オプティミスティック同時実行は、バージョニングされたデータソース AWS AppSync に提供する競合解決戦略です。競合リゾルバーがオプティミスティック同時実行に設定されている場合、着信ミューテーションのバージョンがオブジェクトの実際のバージョンとは異なることが検出されると、競合ハンドラーは着信リクエストを拒否します。GraphQL レスポンス内部では、最新バージョンを持つサーバー上の既存の項目が提供されます。クライアントは、この競合をローカルで処理し、項目の更新バージョンでミューテーションを再試行することが期待されます。

自動マージ

Automerge により、開発者は他の方法で解決できなかった競合を手動でマージするクライアント側のロジックを記述しなくても、競合の解決戦略を簡単に設定することができます。Automerge は、データをマージして競合を解決するときに、厳密なルールセットに従います。Automerge の理念は、GraphQL フィールドの基になるデータ型を中心に展開されています。その内容は次のとおりです。

  • スカラーフィールドでの競合: GraphQL スカラーまたはコレクションではないフィールド (リスト、セット、マップなど)。スカラーフィールドの入力値を拒否し、サーバーに存在する値を選択します。

  • リストの競合: GraphQL 型とデータベース型はリストです。着信リストをサーバー上の既存のリストと連結します。着信ミューテーションのリスト値は、サーバー内のリストの最後に追加されます。重複した値は保持されます。

  • セットの競合: GraphQL 型はリストであり、データベース型はセットです。着信セットとサーバー内の既存のセットを使用して、セットユニオンを適用します。これは、重複するエントリを持たないという、セットのプロパティに準拠しています。

  • 着信ミューテーションが項目に新しいフィールドを追加するか、値が null のときにフィールドに対して着信ミューテーションが実行されたときは、それを既存の項目にマージします。

  • マップ上の競合: データベースの基になるデータ型がマップ (キーと値のドキュメント) の場合、マップの各プロパティを解析して処理する上記のルールを適用します。

Automerge は、更新されたバージョンのリクエストを自動的に検出、マージ、再試行するように設計されており、クライアントは競合するデータを手動でマージする必要がありません。

Automerge がスカラー型で競合を処理する方法の例を示します。出発点として、次のレコードを使用します。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 4 }

クライアントがまだサーバーと同期していないため、着信ミューテーションが項目を更新しようとしている可能性がありますが、それは古いバージョンです。以下のようになります。

{ "id" : 1, "name" : "Nadia", "jersey" : 55, "_version" : 2 }

着信リクエストの古いバージョン 2 に注意してください。このフローの間、Automerge は jersey フィールドの 55 への更新を拒否し、値を 5 のままにすることでデータがマージされます。その結果、項目の次のイメージがサーバーに保存されます。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 5 # version is incremented every time automerge performs a merge that is stored on the server. }

上記の項目の状態がバージョン 5 で、次のイメージで項目を変更しようとする着信ミューテーションがあるとします。

{ "id" : 1, "name" : "Shaggy", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner"] # underlying data type is a Set "points": [24, 30, 27] # underlying data type is a List "_version" : 3 }

着信ミューテーションには、注目すべき 3 つのポイントがあります。スカラーという名前が変更されましたが、2 つの新しいフィールドである、セットの interests およびリストの points が追加されました。このシナリオでは、バージョンの不一致が原因で競合が検出されます。Automerge はそのプロパティに準拠し、名前の変更を拒否します。これは名前がスカラーで、競合しないフィールドのアドオンであるためです。これにより、サーバーに保存された項目は次のように表示されます。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner"] # underlying data type is a Set "points": [24, 30, 27] # underlying data type is a List "_version" : 6 }

項目の更新されたイメージはバージョン 6 となりました。ここで、着信ミューテーション (別のバージョンと不一致) が項目を次のように変換しようとするとします。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "brunch"] # underlying data type is a Set "points": [30, 35] # underlying data type is a List "_version" : 5 }

ここで interests の着信フィールドは、サーバーに存在する 1 つの重複値と 2 つの新しい値を持っていることがわかります。この場合、基になるデータ型はセットであるため、Automerge はサーバーに存在する値と着信リクエストの値を結合し、重複値を除外します。同様に、重複する値が 1 つと新しい値が 1 つある points フィールドには競合があります。しかし、ここで基になるデータ型はリストであるため、Automerge は着信リクエストのすべての値を、サーバーにすでに存在する値の最後に追加します。サーバーに保存されたマージ後のイメージは、次のようになります。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "_version" : 7 }

次に、バージョン 8 で、サーバーに保存された項目が次のようになると仮定します。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "stats": { "ppg": "35.4", "apg": "6.3" } "_version" : 8 }

しかし、着信リクエストは、次のイメージで項目を更新しようとしますが、再びバージョンの不一致が発生します。

{ "id" : 1, "name" : "Nadia", "stats": { "ppg": "25.7", "rpg": "6.9" } "_version" : 3 }

このシナリオでは、サーバーにすでに存在するフィールド (interests、points、jersey) が欠落していることがわかります。また、マップ stats 内の ppg の値は編集中で、新しい値 rpg が追加され、apg は省略されています。Automerge は、省略されたフィールドを保持します (注意: フィールドを削除する予定の場合は、一致するバージョンでリクエストを再試行する必要があります)。したがって、それらは失われません。マップ内のフィールドにも同じルールが適用されるため、ppg への変更は拒否されますが、apg は保持され、新しいフィールド rpg が追加されます。その結果、サーバーに保存された項目は次のようになります。

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "stats": { "ppg": "35.4", "apg": "6.3", "rpg": "6.9" } "_version" : 9 }

lambda

いくつかの Lambda 解決戦略から選択できます。

  • RESOLVE: 既存の項目を、レスポンスペイロードで指定された新しい項目に置き換えます。一度に 1 つの項目に対してのみ、同じオペレーションを再試行できます。現在、DynamoDB PutItem および UpdateItem でサポートされています。

  • REJECT: ミューテーションを拒否し、GraphQL レスポンスの既存の項目でエラーを返します。現在、DynamoDB PutItemUpdateItem、および DeleteItem でサポートされています。

  • REMOVE: 既存の項目を削除します。現在、DynamoDB DeleteItem でサポートされています。

Lambda 呼び出しリクエスト

AWS AppSync DynamoDB リゾルバーは、 で指定された Lambda 関数を呼び出しますLambdaConflictHandlerArn。また、データソースに設定されたものと同じ service-role-arn を使用します。呼び出しのペイロードは以下の構造を持ちます。

{ "newItem": { ... }, "existingItem": {... }, "arguments": { ... }, "resolver": { ... }, "identity": { ... } }

各フィールドの定義は以下のようになります。

newItem

ミューテーションが成功した場合のプレビュー項目。

existingItem

現在、この項目は DynamoDB テーブルに存在しています。

arguments

GraphQL ミューテーションの引数です。

resolver

リ AWS AppSync ゾルバーに関する情報。

identity

呼び出し元に関する情報。このフィールドは、 APIキーでアクセスする場合、null に設定されます。

ペイロードの例:

{ "newItem": { "id": "1", "author": "Jeff", "title": "Foo Bar", "rating": 5, "comments": ["hello world"], }, "existingItem": { "id": "1", "author": "Foo", "rating": 5, "comments": ["old comment"] }, "arguments": { "id": "1", "author": "Jeff", "title": "Foo Bar", "comments": ["hello world"] }, "resolver": { "tableName": "post-table", "awsRegion": "us-west-2", "parentType": "Mutation", "field": "updatePost" }, "identity": { "accountId": "123456789012", "sourceIp": "x.x.x.x", "username": "AIDAAAAAAAAAAAAAAAAAA", "userArn": "arn:aws:iam::123456789012:user/appsync" } }

Lambda 呼び出しレスポンス

PutItem および UpdateItem の競合の解決

ミューテーション を RESOLVE する レスポンスは次の形式である必要があります。

{ "action": "RESOLVE", "item": { ... } }

item フィールドは、基になるデータソースの既存の項目を置き換えるために使用されるオブジェクトを表します。プライマリキーと同期メタデータは、item に含まれている場合は無視されます。

ミューテーション を REJECT する レスポンスは次の形式である必要があります。

{ "action": "REJECT" }

DeleteItem の競合の解決

項目を REMOVE します。レスポンスは次の形式である必要があります。

{ "action": "REMOVE" }

ミューテーション を REJECT する レスポンスは次の形式である必要があります。

{ "action": "REJECT" }

下記の Lambda 関数の例は、呼び出しを行うユーザーとリゾルバー名を確認します。によって作成された場合jeffTheAdmin、リゾルバーの DeletePostオブジェクト、または更新/削除リゾルバーの新しい項目とRESOLVE競合REMOVEします。それ以外の場合、ミューテーションは REJECT です。

exports.handler = async (event, context, callback) => { console.log("Event: "+ JSON.stringify(event)); // Business logic goes here. var response; if ( event.identity.user == "jeffTheAdmin" ) { let resolver = event.resolver.field; switch(resolver) { case "deletePost": response = { "action" : "REMOVE" } break; case "updatePost": case "createPost": response = { "action" : "RESOLVE", "item": event.newItem } break; default: response = { "action" : "REJECT" }; } } else { response = { "action" : "REJECT" }; } console.log("Response: "+ JSON.stringify(response)); return response; }

エラー

以下は、競合解決プロセス中に発生する可能性のあるエラーのリストです。

ConflictUnhandled

競合の検出によりバージョンの不一致が検出され、競合ハンドラーによりミューテーションが拒否された。

例: オプティミスティック同時実行の競合ハンドラーを使用した競合の解決。または、Lambda 競合ハンドラーが REJECT として返される。

ConflictError

競合を解決しようとすると内部エラーが発生する。

例: Lambda 競合ハンドラーが誤った形式のレスポンスを返す。または、指定されたリソース LambdaConflictHandlerArn が見つからないため、Lambda 競合ハンドラーを呼び出せない。

MaxConflicts

競合解決のための最大再試行回数に達した。

例: 同じオブジェクトに対する同時リクエストが多すぎる。競合が解決される前に、オブジェクトは別のクライアントによって新しいバージョンに更新される。

BadRequest

クライアントがメタデータフィールド (_version_ttl_lastChangedAt_deleted) を更新しようとした。

例: クライアントは、更新_versionミューテーションを使用してオブジェクトを更新しようとします。

DeltaSyncWriteError

差分同期レコードの書き込みに失敗した。

例: ミューテーションは成功したが、差分同期テーブルへの書き込み中に内部エラーが発生した。

InternalFailure

内部エラーが発生しました。

UnsupportedOperation

サポートされていないオペレーション 'X'。 データソースバージョニングでは、次のオペレーション (TransactGetItems、PutItem、スキャンBatchGetItem、クエリ、GetItemDeleteItem、、Sync) UpdateItemのみがサポートされます。

例: 競合の検出/解決を有効にして特定のトランザクションおよびバッチオペレーションを使用する。これらのオペレーションは現在サポートされていません。

CloudWatch ログ

がログ AWS AppSync API記録設定をフィールドレベル CloudWatch ログに設定enabledし、フィールドレベルログのログレベルを に設定してログを有効にしている場合ALL、 AWS AppSync は競合の検出および解決情報をロググループに出力します。ログメッセージの形式については、競合の検出と同期のログ記録に関するドキュメントを参照してください。