2010-07-28 3 views
3

Я использую API с другого сайта, который возвращает пару URL-адресов цены, которые мои пользователи используют для покупки виртуальных товаров.Django, Borg pattern, API-вызовы, результаты кэширования

Я должен кэшировать эти результаты не менее часа, так как они не меняют цены на их систему. (И мы хотим сохранить и наши и их пропускную способность.)

После ищу Синглтон в Python я обнаружил шаблон Борга, который, кажется, еще круче, так это то, что я сделал:

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() 

Идея будет использовать это следующим образом:

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

и магазин должен инициализировать правильно, и только получать новую информацию цене, если существующая информация старше одного часа.

Я, кажется, нажимаю их API каждый раз, когда PriceStore инициализируется. Может ли кто-нибудь определить мою проблему? Могу ли я использовать глобальную переменную типа __shared_state в django и ожидать, что она по-прежнему будет содержать информацию о ценах?

Спасибо!

+0

Спасибо людям! Извините, что 3 из вас заметили мою ошибку точно в одно и то же время! Вы, конечно, все в порядке. Это лучший способ кэширования результата API, или вы сделали что-то более холодное? – rdrey

ответ

4

Я, кажется, ударяя их API с каждый раз, когда PriceStore является инициализируется, хотя. Может ли кто-нибудь обнаружить моей проблемой?

Да, это легко заметить:

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

self.lastUpdate = Noneабсолютно гарантирует, что сразу после вызова self.update() будет найти значение self.lastUpdate «s быть None - вы просто заставили его быть так!

Удалить, что self.lastUpdate = None в __init__ и, например, использовать вместо этого

lastUpdate = None 

на класса тела уровня, например, сразу после назначения __shared_state = {} и с тем же выравниванием, что и задание. То, что сделает все так, как вы планируете.

+0

D'OOH! Благодарю. Я должен был положить это, когда я отлаживал его, и у него сначала не был ценовой объект. – rdrey

0

В __init__ вы установили self.lastUpdate = None. Не делай этого.

В частности, не рассмотрим следующий код:

A = PriceStore() 

# some time later 

B = PriceStore() 

Теперь A.lastUpdate == None, которые вы не хотите! Вместо этого попробуйте

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

Таким образом, вы никогда не перезаписываете его.

1

Основная проблема заключается в том, что при создании нового PriceStore вы устанавливаете self.lastUpdate в None (в вашей второй-последней строке). Поэтому, хотя все они разделяют государство, каждый новый объект сжимает государство.

Вместо этого:

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

Еще одна проблема, вы можете столкнуться в том, что в зависимости от того, как развертывается ваш Django, вы можете использовать более одного процесса. У каждого будет своя копия общего состояния.

+0

не будет ли этот «жесткий» код «lastUpdate» всегда иметь значение «Нет»? Нет, думая об этом, это, вероятно, тоже работает. Поскольку {} не означает, что __shared_state всегда пуст. Так будет ли мой код просто перезаписывать этот «Нет» и сохранить его? Да, я не уверен в настройке mod_wsgi на моей машине, но даже если есть 4 процесса apache, я думаю, что api не будет черным списком меня на вызов каждые 15 минут. – rdrey

Смежные вопросы