ValueError: не удалось зафиксировать транзакцию в 5 попытках - PullRequest
0 голосов
/ 31 января 2019

TL; DR Транзакции не обновляют счетчики, как ожидалось

Scenerio:

У меня есть подколлекции с именами projects и activities.Коллекция проектов используется для хранения информации о любых текущих проектах, а коллекция операций служит журналом аудита для любых изменений, происходящих в коллекции проектов.

Я написал облачную функцию, которая запускается для коллекции операций on create event,После создания документа в коллекции действий мне нужно обновить счетчик с именем activityCount в документе, обозначенном projectId в под сборнике проектов.

Облачная функция (некоторые части удалены из-за краткости)следующим образом:

@firestore.transactional
def update_activity_count_in_transaction(transaction, activity):
    """
    updates the activity count for a project
    """
    try:
        # get the project details of associated project at home/{orgId}/projects/{projectId}
        project = activity.project.doc_ref.get(transaction=transaction)

        # get the activity count from the transactional snapshot
        activity_count = project.get(FireBaseConfig.ACTIVITY_COUNT)

        # increment the counter using transaction
        transaction.update(activity.project.doc_ref, {FireBaseConfig.ACTIVITY_COUNT: activity_count + 1})
    except KeyError as err:
        print(err)

        # create activityCount key if not present in projects collection and increment the counter using transaction
        transaction.update(activity.project.doc_ref, {FireBaseConfig.ACTIVITY_COUNT: 1})
    print('transaction success')

    return True


def activity_on_create(event, context):
    """
    update the activity count in projects sub collection
    This is invoked on create event at home/{orgId}/activities/{activityId}
    """

    # parse the event data received from cloud functions into a FireStoreActivity object
    activity = FireStoreActivity(event, context)
    try:
        if not activity.project.id:
            print('no project id')
            return True

        # get firestore transaction object
        # activity.transaction() is equivalent to firestore.client().transaction()
        transaction = activity.transaction()

        # update the counter using transaction
        update_activity_count_in_transaction(transaction, activity)
    except Exception as err:
        pass
    return True

При этом возникает ошибка:

ValueError: Failed to commit transaction in 5 attempts

Трассировка:

File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 333, in run_background_function
    _function_handler.invoke_user_function(event_object)
  File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 199, in invoke_user_function
    return call_user_function(request_or_event)
  File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 196, in call_user_function
    event_context.Context(**request_or_event.context))
  File "/user_code/main.py", line 149, in activity_on_create
    raise err
  File "/user_code/main.py", line 146, in activity_on_create
    update_activity_count_in_transaction(transaction, activity)
  File "/env/local/lib/python3.7/site-packages/google/cloud/firestore_v1beta1/transaction.py", line 327, in __call__
    raise ValueError(msg)
ValueError: Failed to commit transaction in 5 attempts.

Примечание. Эта ошибка возникает случайнои не все время.Но это происходит.

Есть идеи, что здесь могло пойти не так?

1 Ответ

0 голосов
/ 01 февраля 2019

Когда транзакция не удается зафиксировать из-за большого количества одновременных записей в одни и те же целевые документы, клиенты Firestore повторят транзакцию до N раз, прежде чем отказаться.В случае клиента Python Firestore по умолчанию N = 5.Вы можете управлять этим параметром, передавая аргумент max_attempts в вызов метода client.transaction().

...