1

Следующим является частью приложения Python Колбы работает на Google App Engine:Google App Engine memcache.Client.cas() постоянно возвращается значение False для отсутствующих ключей

@app.route('/blabla', methods=['GET']) 
def blabla(): 
    # memcache.add('key', None) # this "fixes" it! 
    memcache_client = memcache.Client() 
    while True: 
     value = memcache_client.gets('key') 
     if value is None: # First time 
      updated_value = 'Bla' 
     else: 
      updated_value = value + ', bla' 
     if memcache_client.cas('key', updated_value): 
      return updated_value 

Начиная с пустым кэшем, если мы делаем последовательные запросы GET к/BlaBla, я бы ожидать, что запросы на возвращение:

Bla 
Bla, bla 
Bla, bla, bla 
. 
. 

(Если по какой-то причине в каком-то момент между .gets() и cas() кэшем получает покраснел, то я бы ожидать, что последовательность перезагрузки, не проблемы .)

Но мы ничего не получаем, потому что memcache_client.cas() постоянно возвращает False навсегда, поэтому программа застревает в while -loop. По-видимому, это происходит потому, что ключ 'key' не существует в начале.

Я знаю это, потому что, если я раскомментирую memcache.add('key', None), это сортирует работы, потому что тогда существует ключ и .cas() счастлив и возвращает True. Но если бы между .add() и .gets() какой-то другой процесс должен был очистить кеш, мы вернемся туда, откуда мы начали, с отсутствующим ключом, и .cas() вернется к возврату False на неопределенный срок. Так что это нехорошее решение.

Почему .cas() не работает, если ключ отсутствует в начале? Или, по крайней мере, почему .cas() не принимает параметр initial_value=, как его родной брат decr()? Это ошибка или функция? Я не могу найти это документально должным образом в любом месте, за исключением того, что Гвидо ван Россум упоминает его в своем single blog post on the matter -reffering к assert он делает, что .gets() не возвращается None, он говорит:

Помимо 2: утверждают, является наивным; на практике вам придется как-то справиться с инициализацией счетчика.

Dank je wel Guido - кто-нибудь знает, как, пожалуйста?

ответ

1

Хорошо, я понял.

@app.route('/blabla', methods=['GET']) 
def blabla(): 
    memcache_client = memcache.Client() 
    while True: 

     if memcache.add('key', 'Bla'): 
      # That's all folks! 
      return 'Bla' 

     # add() failed => the key must already exist, we have to compare-and-set. 

     value = memcache_client.gets(key_name) 

     if value is None: 
      # At the time add() failed the key existed, but now gets() is returning None, 
      # so somebody must have deleted the cache entry in between. 
      # Let's start from scratch. 
      continue 

     updated_value = value + ', bla' 

     if memcache_client.cas(key_name, updated_value): 
      return updated_value 
     else: 
      continue 

Это сложнее, чем мне бы хотелось, но это работает.

Последний else: continue является излишним, но я пишу его, чтобы было ясно, что мы будем продолжать попытки, пока не добьемся успеха.

Хотя на практике вам придется как-то справиться с отказом после нескольких попыток.

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