ブログ/ニュース サイトのコードを書いています。メインページには最新の 10 件の記事があり、すべての記事が変更時間の降順でソートされたアーカイブセクションもあります。アーカイブ セクションでは、カーソルに基づいたページネーションを使用し、2 ページ目から結果をキャッシュします。これは、新しい記事が公開された場合、または既存の記事が何らかの理由で下書きになった場合にのみページが変更されるためです。各ページには 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() 関数をテストしましたが、期待どおりに動作します。データストアに更新を put() してから cacheArchivePages() 関数で fetchArticlesPage() を実行するまでの時間が短すぎたのではないでしょうか? 書き込みトランザクションがまだ終了していないため、古い結果が得られたのではないでしょうか? time.sleep() を使用しようとし、数秒待ってから cacheArchivePages() を呼び出しましたが、その場合、その動作を再現できませんでした。しかし、 time.sleep() は良い考えではないようです。とにかく、その行動の正確な原因と対処方法を知る必要があります。