Задержка чтения в хранилище данных App Engine после put()
Я пишу код для блога/новостного сайта. На главной странице есть 10 последних статей, а также есть раздел архива со всеми статьями, отсортированными по времени изменения по убыванию. В разделе архива я использую разбиение на страницы на основе курсоров и результаты кэширования I, начиная со второй страницы, поскольку страницы изменяются только при публикации новой статьи или существующих по какой-либо причине. На каждой странице 10 статей. Поэтому, когда пользователь нажимает на страницу архива с некоторым номером (а не первым), memcache сначала проверяется на этот номер страницы. Если страница отсутствует, memcache проверяется на курсор для этой страницы, а затем результаты извлекаются из хранилища данных с помощью этого курсора:
class archivePage:
def GET(self, page):
if not page:
articles = memcache.get('archivePage')
if not articles:
articles = fetchArticles()
memcache.set('archivePage', articles)
else:
if int(page) == 0 or int(page) == 1:
raise web.seeother('/archive')
articles = memcache.get('archivePage'+page)
if not articles:
pageCursor = memcache.get('ArchivePageMapping'+page)
if not pageCursor:
pageMapping = ArchivePageMapping.query(ArchivePageMapping.page == int(page)).get()
pageCursor = pageMapping.cursor
memcache.set('ArchivePageMapping'+page, pageCursor)
articles = fetchArticles(cursor=Cursor(urlsafe=pageCursor))
memcache.set('archivePage'+page, articles)
Каждый раз, когда создается новая статья или изменяется статус существующей статьи (черновик/опубликованный), я обновляю кеш для результатов архивных страниц и курсоров. Я делаю это после сохранения статьи в хранилище данных:
class addArticlePage:
def POST(self):
formData = web.input()
if formData.title and formData.content:
article = Article(title=formData.title,
content=formData.content,
status=int(formData.status))
key = article.put()
if int(formData.status) == 1:
cacheArchivePages()
raise web.seeother('/article/%s' % key.id())
def cacheArchivePages():
articles, cursor, moreArticles = fetchArticlesPage()
memcache.set('archivePage', articles)
pageNumber=2
while moreArticles:
pageMapping = ArchivePageMapping.query(ArchivePageMapping.page == pageNumber).get()
if pageMapping:
pageMapping.cursor = cursor.urlsafe()
else:
pageMapping = ArchivePageMapping(page=pageNumber,
cursor=cursor.urlsafe())
pageMapping.put()
memcache.set('ArchivePageMapping'+str(pageNumber), cursor.urlsafe())
articles, cursor, moreArticles = fetchArticlesPage(cursor=cursor)
memcache.set('archivePage'+str(pageNumber), articles)
pageNumber+=1
И вот проблема. Иногда (нет закона, это происходит случайным образом) после обновления кеша я получаю те же результаты и курсоры для архивных страниц, что и до обновления. Например, я добавляю новую статью. Он сохраняется в хранилище данных и отображается на первой странице и на первой странице в архиве (первая страница архива не кэшируется). Но другие страницы архива не обновляются. Я протестировал функцию cacheArchivePages(), и она работает так, как ожидалось. Может ли быть так, что прошло слишком мало времени после того, как я установил() обновление в хранилище данных и до того, как я получаю функциюArticlesPage() в функции cacheArchivePages()? Возможно, транзакция записи еще не закончилась, и поэтому я получаю старые результаты? Я попытался использовать time.sleep() и подождать несколько секунд, прежде чем вызывать cacheArchivePages(), и в этом случае я не смог воспроизвести это поведение, но мне кажется, что time.sleep() не очень хорошая идея. В любом случае мне нужно знать точную причину такого поведения и способы борьбы с ним.
Ответы
Ответ 1
Скорее всего, вы попадаете в "последовательные запросы". При использовании хранилища данных HR запросы могут использовать несколько старых данных, и для данных, написанных put(), должны быть видимыми запросы (нет такой задержки для get() по ключу или id). Задержка, как правило, измеряется в секундах, но я не думаю, что мы гарантируем верхнюю границу - если вы попадаете в неудачный сетевой раздел, может быть, часов, я думаю.
Есть все виды частичных решений: от обмана, когда автор последних записей просматривает результаты запроса на использование запросов предков (у которых есть своя доля ограничений). Вы можете просто предоставить кешу ограниченное время жизни и обновить его при чтении вместо записи.
Удачи!