2016-12-03 4 views
1

Итак, у меня есть значения, которые необходимо обновить в моем хранилище данных. Я использую транзакцию, как показано ниже. После того, как обновление было совершено, я отправляю результат обратно клиенту, давая им знать, что обновление прошло. Затем клиент отправляет другой запрос для обновленного списка элементов. Насколько мне известно, весь код выполняется правильно, никаких ошибок не было, и в итоге я получаю требуемое обновление, как и ожидалось.Google App Engine Datastore, возвращаясь до его обновления в течение нескольких секунд

Моя проблема даже после совершения иногда иногда занимает несколько секунд, прежде чем обновление отобразится в возвращенном списке. Если бы это была просто задержка, которая была бы дрянной, но это хуже, чем это. Список возвращает неправильные/не обновленные значения в течение этого периода времени. Я понимаю, что с этой архитектурой могут возникнуть задержки, но я думал, что вся транзакция была такой, что если бы что-то было обновлено, как ничто не могло бы прочитать старое значение после того, как транзакция захватила нужный элемент? Чтобы увидеть старое значение в течение долгого, долгого времени, кажется неправильным. Гораздо меньше ожидания, пока транзакция не сообщит, что она была совершена, и имеет весь 300 мс + RTT и все еще получает плохие значения в течение нескольких секунд после того, как это якобы было совершено. Что мне здесь не хватает?

/* 
    We don't actually delete a post, we simply replace it with a [removed] 
    version of itself. 
*/ 
router.delete('/', function (req, res) { 

    //Check our parameters 
    if (req.body == null || req.body["Thread"] == null || typeof req.body["Thread"] !== "string") { 
     res.json({ success: false, message: "Thread name was not included as a parameter.", data: null}); 
     return; 
    } 

    if (req.body == null || req.body["PostNumber"] == null) { 
     res.json({ success: false, message: "Post Number was not included as a parameter.", data: null }); 
     return; 
    } 

    if ((parseInt(req.body["PostNumber"]) || 0) < 1) { 
     res.json({ success: false, message: "Post Number was not a valid numeric value.", data: null }); 
     return; 
    } 

    var transaction = datastore.transaction(); 
    transaction.get(datastore.key(['Post', PostName(req.body["Thread"], 6, parseInt(req.body["PostNumber"]))]), function (err, value) { 

     if (err) 
     { 
      res.json({ success: false, message: "Transaction failed.", data: null }); 
      return; 
     } 

     if (value === null) 
     { 
      res.json({ success: false, message: "Post and thread combination does not exist.", data: null }); 
      return; 
     } 

     value.data.CreatorName = "[removed]"; 
     value.data.CreatorFooter = ""; 
     value.data.Contents = "[removed]"; 
     transaction.save(value); 
     transaction.commit(function (err) { 
      if (err) 
      { 
       res.json({ success: false, message: "Transaction failed.", data: null }); 
      } 
      else 
      { 
       res.json({ success: true, message: "Erased post information from table", data: null }); 
      } 
     }); 
    }); 
}); 
+0

Это очень раздражает, если вы не знаете, как это преодолеть. Возможно, эти документы помогают. https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/ - https://dzone.com/articles/better-explaining-cap -теореме –

ответ

3

То, что вы испытываете, называется «возможной консистенцией», и это важная часть архитектуры облачного хранилища данных. Без него Datastore будет намного медленнее для всех запросов.

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

Существует несколько стратегий для работы с возможной консистенцией, но они не применимы/необходимы в вашем случае использования, поскольку обновленные данные: уже доступно для вашего клиентского приложения. Это ваше приложение-клиент инициировало запрос сохранения. Практически во всех ситуациях это означает, что вы можете избежать перезагрузки данных.

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

В очень редком случае при сохранении объекта клиенту требуется загрузить совершенно новый набор данных, который может включать обновленный объект, клиент может поменять объект, возвращенный в запросе, обновленным объектом - или добавить если он отсутствует. Опять же, к моменту появления результатов запроса у вас уже есть полностью обновленный объект из вашего ответа «сохранить объект».