transactWrite в DynamoDB не является ACID в нескольких таблицах

У меня есть две таблицы в DynamoDB, и я хочу выполнить операции PUT и Update для обеих таблиц. Ниже приведены параметры:

      {
    "TransactItems": [
        {
            "Put": {
                "Item": {
                    "ref": 0,
                    "date": 0
                },
                "TableName": "dev-table"
            }
        },
        {
            "Put": {
                "Item": {
                    "ref": 1,
                    "date": 0
                },
                "TableName": "dev-table"
            }
        },
        {
            "Update": {
                "TableName": "dev-table-metadata",
                "Key": {
                    "metaDataKey": "refConsumed"
                },
                "ExpressionAttributeValues": {
                    ":s": 1
                },
                "UpdateExpression": "SET metaDataValue = :s",
                "ReturnValues": "ALL_NEW"
            }
        }
    ]
}

Итак, вот два Put операции происходят на dev-table и один Update операция идет dev-table-metadata

Я запускаю transactWrite в цикле 10 раз, и ответ возвращается нормально, но за несколько итераций я получаю ошибку ниже

TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [None, None, TransactionConflict]

Я предполагаю, что в этих случаях вся транзакция должна быть отменена, но первые две операции Put записываются в таблицу, а последнее обновление - нет.

1 ответ

Я попытался воспроизвести это с помощью сценария, который вы можете увидеть ниже, с двумя операциями помещения в одну таблицу и обновлением в другую в транзакции. Я не смог воспроизвести это. Пожалуйста, включите код, чтобы сделать это воспроизводимым.

Помимо этого, я склонен доверять документации AWS и своему опыту, что это действительно ACID.

- это синхронная и идемпотентная операция записи, которая объединяет до 25 действий записи в одну операцию "все или ничего". Эти действия могут быть нацелены на до 25 отдельных элементов в одной или нескольких таблицах DynamoDB в одной учетной записи AWS и в одном регионе. Совокупный размер элементов транзакции не может превышать 4 МБ. Действия завершаются атомарно, так что либо все они успешны, либо ни одно из них не удается.

- документы (выделено мной)

Моя попытка воспроизвести это:

      import typing

import boto3
import boto3.dynamodb.conditions as conditions

from botocore.exceptions import ClientError

TABLE_1 = "tbl1"
TABLE_2 = "tbl2"


def create_table_if_not_exists(table_name: str):

    try:
        boto3.client("dynamodb").create_table(
            AttributeDefinitions=[{"AttributeName": "PK", "AttributeType": "S"}],
            TableName=table_name,
            KeySchema=[{"AttributeName": "PK", "KeyType": "HASH"}],
            BillingMode="PAY_PER_REQUEST"
        )
    except ClientError as err:
        if err.response["Error"]["Code"] == 'ResourceInUseException':
            # Table already exists
            pass
        else:
            raise err

def transact_write(put_1_value, put_2_value, update_1_value):
    client = boto3.client("dynamodb")
    client.transact_write_items(
        TransactItems=[
            {
                "Put": {
                    "Item": {"PK": {"S": put_1_value}},
                    "TableName": TABLE_1
                }
            },
            {
                "Put": {
                    "Item": {"PK": {"S": put_2_value}},
                    "TableName": TABLE_1
                }
            },
            {
                "Update": {
                    "TableName": TABLE_2,
                    "Key": {
                        "PK": {"S": str(update_1_value)}
                    },
                    "UpdateExpression": "SET itemValue = :value",
                    "ExpressionAttributeValues": {
                        ":value": {"S": "some_value"}
                    }
                }
            }

        ]
    )

if __name__ == "__main__":
    create_table_if_not_exists(TABLE_1)
    create_table_if_not_exists(TABLE_2)

    for n in range(100):
        print(f"Write #{n}")
        transact_write("a", "b", 1)

Другие вопросы по тегам