Ошибка: 10 ABORTED: слишком много разногласий по этим документам.Пожалуйста, попробуйте еще раз - PullRequest
0 голосов
/ 15 сентября 2018

Что означает эта ошибка?

Особенно, что они означают: Пожалуйста, попробуйте еще раз

Означает ли это, что транзакция не удалась? Нужно ли повторно запускать транзакцию вручную? Из того, что я понял из документации,

Транзакция прочитала документ, который был изменен за пределами сделка. В этом случае транзакция автоматически запускается снова. Транзакция повторяется конечное число раз.

Если да, то по каким документам? Ошибка не указывает, о каком документе идет речь. Я просто получаю этот стек:

{Ошибка: 10 ABORTED: слишком много разногласий по этим документам. пожалуйста Попробуйте снова. в Object.exports.createStatusErrornode_modules \ grpc \ src \ common.js: 87: 15) в ClientReadableStream._emitStatusIfDone \ node_modules \ grpc \ src \ client.js: 235: 26) в ClientReadableStream._receiveStatus \ node_modules \ grpc \ src \ client.js: 213: 8) в Object.onReceiveStatus \ node_modules \ grpc \ src \ client_interceptors.js: 1256: 15) в InterceptingListener._callNext node_modules \ grpc \ src \ client_interceptors.js: 564: 42) в InterceptingListener.onReceiveStatus \ node_modules \ grpc \ src \ client_interceptors.js: 614: 8) в C: \ Users \ Tolotra Samuel \ PhpstormProjects \ CryptOcean \ node_modules \ grpc \ src \ client_interceptors.js: 1019: 24 код: 10, метаданные: метаданные {_internal_repr: {}}, подробности: слишком много споров по этим документам. Пожалуйста, попробуйте еще раз.' }

Чтобы воссоздать эту ошибку, просто запустите цикл for в методе db.runTransaction, как указано в документации

Ответы [ 4 ]

0 голосов
/ 08 мая 2019

Найдено maxAttempts в коде runTransaction , который должен изменить 5 попыток по умолчанию (но еще не проверено).

В любом случае, я думаю, что случайное ожидание (плюс в конечном итогеочереди) все еще лучший вариант.

0 голосов
/ 31 октября 2018

Мы столкнулись с той же проблемой с базой данных Firebase Firestore.Даже небольшие фишки с менее чем 30 предметами, которые можно найти, сталкиваются с этой проблемой.

Наше решение состояло не в том, чтобы распределить счетчик, а в том, чтобы увеличить число попыток транзакции и добавить время задержки для этих повторных попыток.

Первым шагом было сохранение действия транзакции какconst witch может быть передана другой функции.

const taskCountTransaction = async transaction => {
  const taskDoc = await transaction.get(taskRef)

  if (taskDoc.exists) {
    let increment = 0
    if (change.after.exists && !change.before.exists) {
      increment = 1
    } else if (!change.after.exists && change.before.exists) {
      increment = -1
    }

    let newCount = (taskDoc.data()['itemsCount'] || 0) + increment
    return await transaction.update(taskRef, { itemsCount: newCount > 0 ? newCount : 0 })
  }

  return null
}

Вторым шагом было создание двух вспомогательных функций.Один для ожидания определенного количества времени, другой для запуска транзакции и обнаружения ошибок.Если возникает ошибка сброса с кодом 10. Мы просто запускаем транзакцию снова для определенного количества попыток.

const wait = ms => { return new Promise(resolve => setTimeout(resolve, ms))}


const runTransaction = async (taskCountTransaction, retry = 0) => {
  try {
    await fs.runTransaction(taskCountTransaction)
    return null
  } catch (e) {
    console.warn(e)
    if (e.code === 10) {
      console.log(`Transaction abort error! Runing it again after ${retry} retries.`)

      if (retry < 4) {
        await wait(1000)
        return runTransaction(taskCountTransaction, ++retry)
      }
    }
  }
}

Теперь, когда у нас есть все, что нам нужно, мы можем просто вызвать нашу вспомогательную функцию с помощью await инаш вызов транзакции будет выполняться дольше, чем вызов по умолчанию, и он будет задерживаться во времени.

await runTransaction(taskCountTransaction)

Что мне нравится в этом решении, так это то, что оно не означает более сложный код и что большая часть уже написанногокод может остаться как есть.Он также использует больше времени и ресурсов только в том случае, если счетчик доходит до того, что ему приходится считать больше предметов.В противном случае время и ресурсы такие же, как если бы у вас были транзакции по умолчанию.

Для увеличения количества элементов мы можем увеличить количество повторных попыток или время ожидания.Оба также влияют на стоимость Firebase.Для части ожидания нам также нужно увеличить время ожидания для нашей функции.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : я не тестировал этот код со стрессом с тысячами или более элементов.В нашем конкретном случае проблемы начались с 20+ предметов, и нам нужно до 50 предметов для задачи.Я проверил это с 200 пунктами, и проблема не появлялась снова.

0 голосов
/ 15 января 2019

Firestore перезапускает транзакцию только конечное число раз. На момент написания это число жестко закодировано как 5 и не может быть изменено . Чтобы избежать перегрузки / раздора, когда многие пользователи используют один и тот же документ, обычно мы используем алгоритм экспоненциальной отсрочки (но это приведет к тому, что транзакции будут выполняться дольше, что может быть приемлемо в некоторых случаях).

Однако, на момент написания, это не было реализовано в Firebase SDK, а - транзакции повторяются немедленно. К счастью, мы можем реализовать наш собственный алгоритм экспоненциального отката в транзакции:

const createTransactionCollisionAvoider = () => {
  let attempts = 0
  return {
    async avoidCollision() {
      attempts++
      await require('delay')(Math.pow(2, attempts) * 1000 * Math.random())
    }
  }
}

… который можно использовать так:

// Each time we run a transaction, create a collision avoider.
const collisionAvoider = createTransactionCollisionAvoider()
db.runTransaction(async transaction => {
  // At the very beginning of the transaction run,
  // introduce a random delay. The delay increases each time
  // the transaction has to be re-run.
  await collisionAvoider.avoidCollision()

  // The rest goes as normal.
  const doc = await transaction.get(...)
  // ...
  transaction.set(...)
})

Примечание: Приведенный выше пример может привести к тому, что транзакция может занять до 1,5 минут. Это хорошо для моего случая использования. Возможно, вам придется настроить алгоритм отсрочки для вашего варианта использования.

0 голосов
/ 15 сентября 2018

Транзакция выполняется несколько раз, если это необходимо, но если считанные значения продолжают обновляться до того, как может произойти запись или запись, в конечном итоге произойдет сбой, поэтому документация, в которой отмечается, что транзакция повторяется с конечным числомраз.Если у вас есть значение, которое часто обновляется как счетчик, рассмотрите другие решения, такие как распределенные счетчики .Если вам нужны более конкретные предложения, я рекомендую вам включить код вашей транзакции в ваш вопрос и некоторую информацию о том, чего вы пытаетесь достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...