Я пишу код для блога/новостного сайта.На главной странице 10 последних статей, а также есть раздел архива со всеми статьями, отсортированными по времени модификации по убыванию.В разделе архива я использую пагинацию на основе курсоры, и я кэширую результаты, начиная со второй страницы, так как страницы c зависает только тогда, когда публикуется новая статья или существующая по какой-то причине попадает в черновики. На каждой странице по 10 статей. Поэтому, когда пользователь попадает на страницу архива с каким-то номером (не первым), 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(), и она работает, как и ожидалось. Может ли быть так, что прошло слишком мало времени после того, как я поместил () обновление в хранилище данных и до того, как я выполнил fetchArticlesPage () в функции cacheArchivePages ()? Может быть, транзакция записи еще не завершилась, и поэтому я получаю старые результаты? Я попытался использовать time.sleep() и подождать несколько секунд перед вызовом cacheArchivePages(), и в этом случае я не смог воспроизвести такое поведение, но мне кажется, что time.sleep() не очень хорошая идея. В любом случае мне нужно знать точную причину такого поведения и как с этим бороться.