Scrivo un codice per un blog/sito di notizie. La pagina principale contiene 10 articoli più recenti e inoltre c'è una sezione di archivio con tutti gli articoli ordinati per tempo di modifica decrescente. Nella sezione archivio utilizzo l'impaginazione basata sui cursori e memorizzo i risultati della cache a partire dalla seconda pagina in quanto le pagine vengono modificate solo quando viene pubblicato un nuovo articolo o se per alcune ragioni le bozze vengono applicate alle bozze. Ogni pagina ha 10 articoli. Pertanto, quando un utente raggiunge una pagina di archivio con un numero (non il primo) memcache viene controllato per ottenere prima i risultati del numero di pagina. Se la pagina non è lì, memcache viene controllato per il cursore per quella pagina e poi i risultati vengono recuperati dal datastore usando quel cursore:Lettura ritardo nel datastore dell'App Engine dopo put()
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)
Ogni volta che viene creato un nuovo articolo o lo stato di un articolo esistente viene modificata (bozza/pubblicato) Rinnovo la cache per i risultati e i cursori delle pagine di archivio. Lo faccio dopo aver salvato un articolo sul datastore:
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
E qui arriva il problema. A volte (non c'è nessuna legge, succede casualmente) dopo aver aggiornato la cache ottengo gli stessi risultati e cursori per le pagine di archivio come prima del refresh. Ad esempio aggiungo un nuovo articolo. Viene salvato nel datastore e viene visualizzato nella prima pagina e nella prima pagina nell'archivio (la prima pagina dell'archivio non viene memorizzata nella cache). Ma altre pagine di archivio non sono aggiornate. Ho testato la mia funzione cacheArchivePages() e funziona come previsto. Potrebbe essere passato così poco tempo dopo aver messo() un aggiornamento al datastore e prima di I fetchArticlesPage() nella funzione cacheArchivePages()? Forse la transazione scritta non è ancora finita e quindi ottengo risultati vecchi? Ho provato a utilizzare time.sleep() e attendere alcuni secondi prima di chiamare cacheArchivePages() e in quel caso non ero in grado di riprodurre questo comportamento, ma mi sembra che time.sleep() non sia una buona idea. Ad ogni modo ho bisogno di conoscere la causa esatta di quel comportamento e come affrontarlo.
Grazie mille Guido! Dovrei prestare maggiore attenzione alla coerenza dei dati e tenere a mente le caratteristiche del datastore delle risorse umane. In questo caso particolare è facile per me confrontare i vecchi risultati e quelli nuovi e se sono gli stessi per riavviare la query. – wombatonfire
Ho upvoted perché "use ancestor queries" è esattamente ciò che ha risolto il problema di ritardo nella mia app, grazie Guido. – Deleplace