2010-07-28 2 views
3

J'utilise une API d'un site différent qui renvoie deux adresses URL de prix que mes utilisateurs utilisent pour acheter des biens virtuels.Django, modèle Borg, appels d'API, résultats de la mise en cache

Je suis censé mettre en cache ces résultats pendant au moins une heure, car ils ne modifient pas beaucoup les prix sur leur système. (Et nous voulons sauver nos deux années et leur bande passante.)

Après avoir cherché années singleton en Python j'ai découvert le modèle de borg, qui semble encore plus cool, donc ce que je l'ai fait:

def fetchPrices(): 
    #uses urllib2.urlopen() to fetch prices 
    #parses results with ElementTree 
    return prices 

class PriceStore(): 
    __shared_state = {} 

    def update(self): 
     if self.lastUpdate is not None and (datetime.now() - self.lastUpdate).seconds >= 3600: 
      self.prices = fetchPrices() 
      self.lastUpdate = datetime.now() 
     elif self.lastUpdate is not None: 
      return 
     else: 
      self.lastUpdate = datetime.now() - timedelta(hours=1) 
      self.update() 

    def __init__(self): 
     self.__dict__ = self.__shared_state 
     self.lastUpdate = None 
     self.update() 

L'idée est d'utiliser ce de la manière suivante:

store = PriceStore() 
url = store.prices['2.9900']['url'] 

et le magasin doit initialiser correctement et ne chercher de nouvelles informations de point de prix, si l'information existante est plus d'une heure. Il semble que je tape sur leur API à chaque fois que PriceStore est initialisé, par contre. Quelqu'un peut-il repérer mon problème? Puis-je utiliser une variable globale comme __shared_state dans django et m'attendre à ce qu'elle contienne toujours des informations de prix?

Merci!

+0

Merci les gens! Désolé que 3 d'entre vous aient repéré mon erreur exactement au même moment! Vous allez bien sûr bien sûr. Est-ce la meilleure façon de mettre en cache un résultat d'API, ou avez-vous fait quelque chose de plus cool? – rdrey

Répondre

4

me semble être frapper leur API avec chaque fois que PriceStore est initialisé, cependant. Quelqu'un peut-il repérer mon problème?

Eh oui, il est facile à repérer:

def __init__(self): 
    self.__dict__ = self.__shared_state 
    self.lastUpdate = None 

le self.lastUpdate = Nonegarantit absolument que l'appel suivant immédiatement à self.update() trouvera la valeur de self.lastUpdate être None - vous venez obligé à être alors!

Retirer self.lastUpdate = None que dans le __init__ et, par exemple, utiliser à la place un corps

lastUpdate = None 

à classe niveau, par exemple, juste après l'affectation __shared_state = {} et avec le même alignement que cette affectation. Que fera fonctionner les choses comme vous l'avez prévu.

+0

D'OOH! Merci. Je dois avoir mis cela quand je le déboguais et qu'il n'avait pas d'objet de prix au début. – rdrey

0

Dans __init__, vous définissez self.lastUpdate = None. Ne fais pas ça.

Plus précisément, considérez le code suivant:

A = PriceStore() 

# some time later 

B = PriceStore() 

maintenant A.lastUpdate == Aucun, que vous ne vouliez pas! Au lieu de cela, essayez

if "lastUpdate" not in self.__dict__: 
    self.lastUpdate = None 

De cette façon, vous ne l'écraser.

1

Votre problème principal est que lorsque vous créez un nouveau PriceStore, vous définissez self.lastUpdate sur None (dans l'avant-dernière ligne). Donc, bien qu'ils partagent tous l'état, chaque nouvel objet clobbers l'état.

faire ce lieu:

class PriceStore(): 
    __shared_state = {'lastUpdate': None} 

Un autre problème que vous pourriez faire face est que, selon la façon dont votre Django est déployé, vous pouvez utiliser plus d'un processus. Chacun aurait sa propre copie de l'état partagé.

+0

est-ce que ce code hard 'lastUpdate' ne serait pas toujours aussi? Non, en y réfléchissant, cela fonctionne probablement aussi. Puisque {} ne signifie pas que __shared_state est toujours vide. Alors mon code écrase-t-il simplement celui-là et le sauvegarde-t-il? Ouais, je ne suis pas sûr de l'installation de mod_wsgi sur ma machine non plus, mais même s'il y a 4 processus apache, je pense que l'API ne me mettra pas sur liste noire pour un appel toutes les 15 minutes. – rdrey

Questions connexes