Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Rilevamento e sincronizzazione dei conflitti
Origini dati con versione
AWS AppSync attualmente supporta il controllo delle versioni su sorgenti dati DynamoDB. Le operazioni di rilevamento dei conflitti, risoluzione dei conflitti e sincronizzazione richiedono un'origine dati Versioned
. Quando si abilitano le versioni multiple su un'origine dati, AWS AppSync automaticamente consentirà di:
-
Migliorare gli elementi con i metadati del controllo delle versioni degli oggetti.
-
Registrare le modifiche apportate agli elementi con mutazioni AWS AppSync a una tabella Delta.
-
Gestire gli elementi eliminati nella tabella Base con una "rimozione definitiva" per un periodo di tempo configurabile.
Configurazione origine dati con versione
Quando si attivano le versioni multiple in un'origine dati DynamoDB, specificare i seguenti campi:
-
BaseTableTTL
-
Il numero di minuti per mantenere gli elementi eliminati nella tabella Base con una "rimozione definitiva", un campo di metadati che indica che l'elemento è stato eliminato. È possibile impostare questo valore su 0 se si desidera che gli elementi vengano rimossi immediatamente quando vengono eliminati. Questo campo è obbligatorio.
-
DeltaSyncTableName
-
Il nome della tabella in cui vengono memorizzate le modifiche apportate agli elementi con mutazioni AWS AppSync . Questo campo è obbligatorio.
-
DeltaSyncTableTTL
-
Numero di minuti per conservare gli elementi nella tabella Delta. Questo campo è obbligatorio.
Tabella di sincronizzazione Delta
AWS AppSync attualmente supporta Delta Sync Logging per le mutazioni utilizzandoPutItem
UpdateItem
, e le operazioniDeleteItem
DynamoDB.
Quando una mutazione AWS AppSync modifica un elemento in un'origine dati con versione, un record di tale modifica verrà memorizzato in una tabella Delta ottimizzata per gli aggiornamenti incrementali. Puoi scegliere di utilizzare diverse tabelle Delta (ad esempio una per tipo, una per area di dominio) per altre fonti di dati con versioni o una singola tabella Delta per la tua API. AWS AppSync consiglia di non utilizzare una singola tabella Delta per più API per evitare la collisione delle chiavi primarie.
Lo schema richiesto per questa tabella è il seguente:
-
ds_pk
-
Valore stringa utilizzato come chiave di partizione. È costruito concatenando il nome della fonte dati di base e il formato ISO 8601 della data in cui è avvenuta la modifica (ad es.
Comments:2019-01-01
).Quando il
customPartitionKey
flag del modello di mappatura VTL è impostato come nome della colonna della chiave di partizione (vedi Resolver Mapping Template Reference per DynamoDB nella Guida per gliAWS AppSync sviluppatori), il formato delleds_pk
modifiche e la stringa vengono costruiti aggiungendogli il valore della chiave di partizione nel nuovo record nella tabella Base. Ad esempio, se il record nella tabella Base ha un valore della chiave di partizione1a
e un valore della chiave di ordinamento pari a2b
, il nuovo valore della stringa sarà:Comments:2019-01-01:1a
. -
ds_sk
-
Un valore stringa utilizzato come chiave di ordinamento. Viene costruito concatenando il formato ISO 8601 dell'ora in cui è avvenuta la modifica, la chiave primaria dell'elemento e la versione dell'elemento. La combinazione di questi campi garantisce l'unicità di ogni voce nella tabella Delta (ad esempio per un orario, un ID
1a
e una versione di2
, questo sarebbe09:30:00:1a:2
).09:30:00
Quando il
customPartitionKey
flag del modello di mappatura VTL è impostato sul nome della colonna della chiave di partizione (vedi Resolver Mapping Template Reference per DynamoDB nella Guida per gliAWS AppSync sviluppatori), il formato delleds_sk
modifiche e la stringa vengono costruiti sostituendo il valore della chiave combinata con il valore della chiave di ordinamento nella tabella Base. Utilizzando l'esempio precedente, se il record nella tabella Base ha un valore della chiave di partizione1a
e un valore della chiave di ordinamento pari a2b
, il nuovo valore della stringa sarà:09:30:00:2b:3
. -
_ttl
-
Un valore numerico che memorizza il timestamp, in secondi dall'epoca, quando un elemento deve essere rimosso dalla tabella Delta. Questo valore viene determinato aggiungendo il valore
DeltaSyncTableTTL
configurato nell'origine dati nel momento in cui si è verificata la modifica. Questo campo deve essere configurato come Attributo TTL DynamoDB.
Il ruolo IAM configurato per l'utilizzo con la tabella Base deve contenere anche le autorizzazioni per operare nella tabella Delta. In questo esempio, viene visualizzato il criterio delle autorizzazioni per una tabella Base denominata Comments
e una tabella Delta denominata ChangeLog
:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Resource": [ "arn:aws:dynamodb:us-east-1:000000000000:table/Comments", "arn:aws:dynamodb:us-east-1:000000000000:table/Comments/*", "arn:aws:dynamodb:us-east-1:000000000000:table/ChangeLog", "arn:aws:dynamodb:us-east-1:000000000000:table/ChangeLog/*" ] } ] }
Metadati origine dati con versioni
AWS AppSync gestisce i campi di metadati sulle fonti diVersioned
dati per tuo conto. La modifica di questi campi può causare errori nell'applicazione o perdita di dati. Questi campi includono:
-
_version
-
Un contatore monotonicamente crescente che viene aggiornato ogni volta che si apporta una modifica a un elemento.
-
_lastChangedAt
-
Un valore numerico che memorizza il timestamp, in millisecondi dall'epoca, al momento dell'ultima modifica di un elemento.
-
_deleted
-
Un valore booleano "contrassegnato per la rimozione definitiva" che indica che un elemento è stato eliminato. Questo può essere utilizzato dalle applicazioni per rimuovere gli elementi eliminati dagli archivi dati locali.
-
_ttl
-
Un valore numerico che memorizza il timestamp, in secondi dall'epoca, quando un elemento deve essere rimosso dall'origine dati sottostante.
-
ds_pk
-
Valore stringa utilizzato come chiave di partizione per le tabelle Delta.
-
ds_sk
-
Valore stringa utilizzato come chiave di ordinamento per le tabelle Delta.
gsi_ds_pk
-
Un attributo di valore di stringa generato per supportare un indice secondario globale come chiave di partizione. Sarà incluso solo se sia i flag che
customPartitionKey
populateIndexFields
i flag sono abilitati nel modello di mappatura VTL (vedi Resolver Mapping Template Reference per DynamoDB nella Guida per gliAWS AppSync sviluppatori). Se abilitato, il valore verrà costruito concatenando il nome dell'origine dati di base e il formato ISO 8601 della data in cui è avvenuta la modifica (ad esempio, se la tabella Base è denominata Commenti, questo record verrà impostato comeComments:2019-01-01
). gsi_ds_sk
-
Un attributo di valore di stringa generato per supportare un indice secondario globale come chiave di ordinamento. Sarà incluso solo se sia i flag che
customPartitionKey
populateIndexFields
i flag sono abilitati nel modello di mappatura VTL (vedi Resolver Mapping Template Reference per DynamoDB nella Guida per gliAWS AppSync sviluppatori). Se abilitato, il valore verrà costruito concatenando il formato ISO 8601 dell'ora in cui è avvenuta la modifica, la chiave di partizione dell'elemento nella tabella Base, la chiave di ordinamento dell'elemento nella tabella Base e la versione dell'elemento (ad esempio, per un periodo di09:30:00
, un valore della chiave di partizione di1a
, un valore della chiave di2b
ordinamento e la versione di3
, questo sarebbe09:30:00:1a#2b:3
).
Questi campi di metadati influiranno sulle dimensioni complessive degli elementi nell'origine dati sottostante. AWS AppSync consiglia di riservare la dimensione massima della chiave primaria di 500 byte per i metadati delle fonti di dati con versioni durante la progettazione dell'applicazione. Per utilizzare questi metadati nelle applicazioni client, includere i campi _version
, _lastChangedAt
e _deleted
nei tipi GraphQL e nel set di selezione per le mutazioni.
Rilevamento e risoluzione dei conflitti
Quando si verificano scritture simultanee con AWS AppSync, è possibile configurare strategie di rilevamento e risoluzione dei conflitti per gestire gli aggiornamenti in modo appropriato. Il rilevamento dei conflitti determina se la mutazione è in conflitto con l'elemento scritto effettivo nell'origine dati. Il rilevamento dei conflitti è abilitato impostando il valore nelconflictDetection
campo SyncConfig perVERSION
.
La risoluzione dei conflitti è l'azione che viene eseguita nel caso in cui venga rilevato un conflitto. Ciò viene determinato impostando il campo Conflict Handler in SyncConfig. Esistono tre strategie di risoluzione dei conflitti:
-
OPTIMISTIC_CONCURRENCY
-
AUTOMERGE
-
LAMBDA
Ognuna di queste strategie di risoluzione dei conflitti è spiegata nei dettagli di seguito.
Le versioni vengono incrementate automaticamente AppSync durante le operazioni di scrittura e non devono essere modificate dai client o dall'esterno di un resolver configurato con un'origine dati abilitata alla versione. Ciò cambierà il comportamento di coerenza del sistema e potrebbe comportare la perdita di dati.
Optimistic Concurrency
Optimistic Concurrency è una strategia di risoluzione dei conflitti che AWS AppSync fornisce per le origini dati con versioni. Quando il risolutore dei conflitti è impostato su Optimistic Concurrency, se viene rilevata una mutazione in ingresso per avere una versione diversa dalla versione effettiva dell'oggetto, il gestore dei conflitti rifiuterà semplicemente la richiesta in ingresso. All'interno della risposta GraphQL, verrà fornito l'elemento esistente sul server con la versione più recente. Il client dovrebbe quindi gestire questo conflitto localmente e riprovare la mutazione con la versione aggiornata dell'elemento.
Automerge
Automerge offre agli sviluppatori un modo semplice per configurare una strategia di risoluzione dei conflitti senza scrivere logica lato client per unire manualmente i conflitti che non erano in grado di essere gestiti da altre strategie. Automerge aderisce a un set di regole rigoroso quando si uniscono i dati per risolvere i conflitti. I principi di Automerge ruotano attorno al tipo di dati sottostante del campo GraphQL. Essi sono i seguenti:
-
Conflitto su un campo scalare: scalare GraphQL o qualsiasi campo che non sia una raccolta (ad esempio List, Set, Map). Rifiuto del valore in ingresso per il campo scalare e selezione del valore esistente nel server.
-
Conflitto su un elenco: il tipo GraphQL e il tipo di database sono elenchi. Concatenamento dell'elenco in entrata con l'elenco esistente nel server. I valori di elenco nella mutazione in arrivo verranno aggiunti alla fine dell'elenco nel server. I valori duplicati verranno mantenuti.
-
Conflitto su un set: il tipo GraphQL è un elenco e il tipo di database è un set. Applicazione di un insieme unione utilizzando il set in ingresso e il set esistente nel server. Questo aderisce alle proprietà di un set, vale a dire nessuna voce duplicata.
-
Quando una mutazione in entrata aggiunge un nuovo campo all'elemento o viene creata su un campo con il valore di
null
, uniscilo all'elemento esistente. -
Conflitto su una mappa: quando il tipo di dati sottostante nel database è una mappa (ad esempio documento chiave-valore), applicare le regole di cui sopra mentre analizza ed elabora ciascuna proprietà della mappa.
Automerge è progettato per rilevare, unire e riprovare automaticamente le richieste con una versione aggiornata, assolvendo il client dalla necessità di unire manualmente i dati in conflitto.
Per mostrare un esempio di come Automerge gestisce un conflitto su un tipo scalare. Useremo il seguente record come punto di partenza.
{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 4 }
Ora una mutazione in arrivo potrebbe tentare di aggiornare l'elemento ma con una versione precedente poiché il client non è ancora sincronizzato con il server. Dovrebbe essere simile a questo:
{ "id" : 1, "name" : "Nadia", "jersey" : 55, "_version" : 2 }
Si noti la versione obsoleta di 2 nella richiesta in entrata. Durante questo flusso, Automerge unirà i dati rifiutando l'aggiornamento del campo "jersey" a "55" e manterrà il valore a "5" con conseguente salvataggio della seguente immagine dell'elemento nel server.
{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 5 # version is incremented every time automerge performs a merge that is stored on the server. }
Dato lo stato dell'elemento mostrato sopra alla versione 5, ora supponiamo che una mutazione in entrata tenti di cambiare l'elemento con la seguente immagine:
{ "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 }
La mutazione in entrata ha tre punti di interesse. Il nome, uno scalare, è stato modificato ma sono stati aggiunti due nuovi campi "interessi", un Set, "punti" e un Elenco. In questo scenario, verrà rilevato un conflitto a causa della mancata corrispondenza della versione. Automerge aderisce alle sue proprietà e rifiuta la modifica del nome data la sua natura scalare e l'add-on ai campi non in conflitto. In questo modo, l'elemento che viene salvato nel server viene visualizzato come segue.
{ "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 }
Con l'immagine aggiornata dell'elemento con la versione 6, ora supponiamo che una mutazione in entrata (con un'altra mancata corrispondenza della versione) cerchi di trasformare l'elemento nel seguente modo:
{ "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 }
Qui osserviamo che il campo in entrata per "interessi" ha un valore duplicato che esiste nel server e due nuovi valori. In questo caso, poiché il tipo di dati sottostante è un Set, Automerge combinerà i valori esistenti nel server con quelli nella richiesta in arrivo e rimuoverà eventuali duplicati. Allo stesso modo c'è un conflitto nel campo "punti" in cui c'è un valore duplicato e un nuovo valore. Ma poiché il tipo di dati sottostante qui è un elenco, Automerge aggiungerà semplicemente tutti i valori nella richiesta in entrata alla fine dei valori già esistenti nel server. L'immagine risultante unita memorizzata sul server apparirà come segue:
{ "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 }
Ora supponiamo che l'elemento memorizzato nel server appaia come segue, nella versione 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 }
Ma supponiamo anche che una richiesta in entrata tenti di aggiornare l'elemento con la seguente immagine, ancora una volta con una mancata corrispondenza della versione:
{ "id" : 1, "name" : "Nadia", "stats": { "ppg": "25.7", "rpg": "6.9" } "_version" : 3 }
Ora, in questo scenario, possiamo vedere che i campi che già esistono nel server sono mancanti (interessi, punti, jersey). Inoltre, il valore per "ppg" all'interno della mappa "statistiche" viene modificato, viene aggiunto un nuovo valore "rpg" e "apg" viene omesso. Automerge conserva i campi che sono stati omessi (nota: se i campi sono destinati a essere rimossi, allora la richiesta deve essere riprovata con la versione corrispondente), e quindi non andranno persi. Applicherà anche le stesse regole ai campi all'interno delle mappe e quindi la modifica a "ppg" verrà rifiutata mentre "apg" è conservato e "rpg", un nuovo campo, viene aggiunto. L'elemento risultante memorizzato nel server verrà ora visualizzato come:
{ "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
Opzioni di risoluzione dei conflitti:
-
RESOLVE
: sostituire l'elemento esistente con un nuovo elemento fornito nel carico utile di risposta. È possibile riprovare la stessa operazione solo su un singolo elemento alla volta. Attualmente supportato per DynamoDBPutItem
eUpdateItem
. -
REJECT
: rifiutare la mutazione e restituire un errore con l'elemento esistente nella risposta GraphQL. Attualmente supportato per DynamoDBPutItem
,UpdateItem
eDeleteItem
. -
REMOVE
: rimuovere l'elemento esistente. Attualmente supportato per DynamoDBDeleteItem
.
La richiesta di invocazione Lambda
Il resolverAWS AppSync DynamoDB richiama la funzione Lambda specificata inLambdaConflictHandlerArn
. Utilizza lo stesso service-role-arn
configurato per l'origine dati. Il payload dell'invocazione ha la seguente struttura:
{ "newItem": { ... }, "existingItem": {... }, "arguments": { ... }, "resolver": { ... }, "identity": { ... } }
I campi sono definiti come segue:
-
newItem
-
L'elemento di anteprima, se la mutazione è riuscita.
-
existingItem
-
L'elemento attualmente risiede nella tabella DynamoDB.
-
arguments
-
Gli argomenti della mutazione GraphQL.
-
resolver
-
Informazioni sul resolver AWS AppSync.
-
identity
-
Informazioni sul chiamante. Questo campo è impostato su null, se l'accesso avviene con chiave API.
Esempio di payload:
{ "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" } }
La risposta all'invocazione Lambda
Per PutItem
e risoluzione UpdateItem
dei conflitti
Rifiuto della mutazione (RESOLVE
). La risposta deve essere nel seguente formato.
{ "action": "RESOLVE", "item": { ... } }
Il campo item
rappresenta un oggetto che verrà utilizzato per sostituire l'elemento esistente nell'origine dati sottostante. La chiave primaria e i metadati di sincronizzazione verranno ignorati se inclusi in item
.
Rifiuto della mutazione (REJECT
). La risposta deve essere nel seguente formato.
{ "action": "REJECT" }
Per la risoluzione dei conflitti DeleteItem
REMOVE
l'articolo. La risposta deve essere nel seguente formato.
{ "action": "REMOVE" }
Rifiuto della mutazione (REJECT
). La risposta deve essere nel seguente formato.
{ "action": "REJECT" }
La funzione Lambda di esempio qui sotto controlla chi effettua la chiamata e il nome del resolver. Se è stato creato dajeffTheAdmin
,REMOVE
l'oggetto per il DeletePost risolutore oRESOLVE
è in conflitto con un nuovo elemento per i risolutori Update/Put. In caso contrario, la mutazione è 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; }
Errori
-
ConflictUnhandled
-
Rilevamento dei conflitti individua una mancata corrispondenza della versione e il gestore dei conflitti rifiuta la mutazione.
Esempio: risoluzione dei conflitti con un gestore di conflitti di Optimistic Concurrency. Oppure, il gestore di conflitti Lambda è stato restituito con
REJECT
. -
ConflictError
-
Si verifica un errore interno quando si tenta di risolvere un conflitto.
Esempio: il gestore di conflitti Lambda ha restituito una risposta non valida. In alternativa, non è possibile richiamare il gestore di conflitti Lambda perché la risorsa fornita
LambdaConflictHandlerArn
non viene trovata. -
MaxConflicts
-
Sono stati raggiunti tentativi massimi per la risoluzione dei conflitti.
Esempio: troppe richieste simultanee sullo stesso oggetto. Prima che il conflitto venga risolto, l'oggetto viene aggiornato a una nuova versione da un altro client.
-
BadRequest
-
Il client tenta di aggiornare i campi dei metadati (
_version
,_ttl
,_lastChangedAt
,_deleted
).Esempio: il client tenta di aggiornare _version di un oggetto con una mutazione di aggiornamento.
-
DeltaSyncWriteError
-
Impossibile scrivere il record di sincronizzazione delta.
Esempio: la mutazione è riuscita, ma si è verificato un errore interno durante il tentativo di scrivere nella tabella di sincronizzazione delta.
-
InternalFailure
-
Si è verificato un errore interno.
CloudWatch Registri
Se un'AWS AppSync API ha abilitato CloudWatch i log con le impostazioni di registrazione impostate su Registri a livello di campoenabled
e a livello di registro per i registri a livello di campo impostate suALL
,AWS AppSync invierà le informazioni di rilevamento e risoluzione dei conflitti al gruppo di log. Per informazioni sul formato dei messaggi di registro, consulta la documentazione relativa al rilevamento conflitti e alla registrazione di sincronizzazione.
1.000.000 di operazioni di sincronizzazione
Le fonti di dati con versioni supportanoSync
operazioni che consentono di recuperare tutti i risultati da una tabella DynamoDB e quindi ricevere solo i dati modificati dall'ultima query (gli aggiornamenti delta). Quando AWS AppSync riceve una richiesta per un'operazione Sync
, utilizza i campi specificati nella richiesta per stabilire se è necessario accedere alla tabella Base o alla tabella Delta .
-
Se il
lastSync
campo non è specificato, viene eseguita unaScan
nella tabella Base. -
Se il campo
lastSync
è specificato, ma il valore è prima delcurrent moment - DeltaSyncTTL
, viene eseguita unaScan
sulla tabella di base. -
Se il campo
lastSync
è specificato e il valore è attivo o dopocurrent moment - DeltaSyncTTL
, viene eseguita unaQuery
sulla tabella Delta.
AWS AppSync restituisce ilstartedAt
campo al modello di mappatura delle risposte per tutte leSync
operazioni. Il campo startedAt
è il momento, in millisecondi dall'epoca, in cui è iniziata l'operazione Sync
che è possibile memorizzare localmente e utilizzare in un'altra richiesta. Se un token di paginazione è stato incluso nella richiesta, questo valore sarà lo stesso di quello restituito dalla richiesta per la prima pagina di risultati.
Per informazioni sul formato per i modelli di mappatura Sync
, consulta il riferimento del modello di mappatura.