【问题标题】:Google App Engine NDB database corrupted?Google App Engine NDB 数据库已损坏?
【发布时间】:2015-07-29 10:57:19
【问题描述】:

我不断收到随机错误,例如:

suspended generator _get_tasklet(context.py:329) raised ProtocolBufferDecodeError(corrupted)

suspended generator put(context.py:796) raised ValueError(Expecting , delimiter: line 1 column 440 (char 440))

suspended generator put(context.py:796) raised ValueError(Invalid \escape: line 1 column 18002 (char 18002))

suspended generator _get_tasklet(context.py:329) raised ProtocolBufferDecodeError(truncated)

直到几天前一切正常,我还没有进行任何更改。当我重新启动我的应用程序时,一切都很好,大约五分钟,直到我得到一个

suspended generator _get_tasklet(context.py:329) raised ProtocolBufferDecodeError(corrupted)

在那之后,我在每个数据库 put 或 get 上都会遇到其他错误之一。导致错误的表和代码每次都不一样。我不知道从哪里开始,因为错误每次都在一个新的地方。 这些只是常规的数据库放置和获取,例如

ndbstate = NdbStateJ.get_by_id(self.screen_name)

ndbstate.put()

Google 搜索无法为我指明任何特定方向。有任何想法吗? 错误

Expecting , delimiter: line 1 column 440 (char 440)

可能是因为某些表中的某些字段类型是 JSON。但是为什么突然?

所以也许我在某处没有正确转义,例如使用 r'{...}',但如果某处有错误条目,如果我无法查询,我该如何解决?为什么它会破坏所有查询的整个表?为什么它是随机的。每次都不是同一个查询。

这是一个表格示例

class NdbStateJ(ndb.Model):
    last_id = ndb.IntegerProperty()
    last_search_id = ndb.IntegerProperty()
    last_geo_id = ndb.IntegerProperty()
    mytweet_num = ndb.IntegerProperty()
    mentions_processed = ndb.JsonProperty()
    previous_follower_responses = ndb.JsonProperty()
    my_tweets_tweeted = ndb.JsonProperty()
    responses_already_used = ndb.JsonProperty()
    num_followed_by_cyborg = ndb.IntegerProperty(default=0)
    num_did_not_follow_back = ndb.IntegerProperty(default=0)
    language_model_vector = ndb.FloatProperty(repeated=True)
    follow_wait_counter = ndb.IntegerProperty(default=0)

这里是一个创建表格的例子

ndbstate = NdbStateJ(id=screen_name,
last_id = 37397357946732541,
last_geo_id = 37397357946732541,
last_search_id = 0,
mytweet_num = 0,
mentions_processed = [],
previous_follower_responses = [],
my_tweets_tweeted = [],
responses_already_used= [],
language_model_vector = [])
ndbstate.put()

【问题讨论】:

  • 如果您尝试上传到不同的应用程序并从那里运行,您会收到相同的错误吗?如果您从未得到它,那么它可能是您的其他应用程序损坏。另外,“重启我的应用”是什么意思
  • 酷。谢谢。我终于弄明白了。那是一头野兽。见下文。

标签: python json google-app-engine


【解决方案1】:

导致问题的数据库中的 JSON 格式不正确。我不知道为什么这个问题突然开始到处发生;也许谷歌方面发生了一些变化,或者我没有充分检查,新用户能够输入格式错误的数据。谁知道呢。

为了解决这个问题,我从https://stackoverflow.com/users/1011633/nizz 回复App Engine return JSON from JsonPropertyhttps://stackoverflow.com/users/1709587/mark-amery 回复How to escape special characters in building a JSON string?https://stackoverflow.com/users/1639625/tobias-k 回复How do I automatically fix an invalid JSON string? 获得灵感。

我将ndb.JsonProperty() 替换为ExtendedJsonProperty,其中扩展版本类似于下面的代码。

import json
from google.appengine.ext import ndb 
import logging
logging.getLogger().setLevel(logging.DEBUG)
import re

class ExtendedJsonProperty(ndb.BlobProperty):
    # Inspired by https://stackoverflow.com/questions/18576556/app-engine-return-json-from-jsonproperty
    def _to_base_type(self, value):
        logging.debug('Dumping value '+str(value))
        try:
            return json.dumps(value) 
        except Exception as e:
            logging.warning(('trying to fix error dumping from database: ') +str(e))
            return fix_json(value,json.dumps)

    def _from_base_type(self, value):
        # originally return json.loads(value)
        logging.debug('Loading value '+str(value))
        try:
            return json.loads(value)
        except Exception as e:
            logging.warning(('trying to fix error loading from database: ') +str(e))
            return fix_json(value,json.loads)        

def fix_json(s,json_fun):
    for _i in range(len(s)):
        try:
            result = json_fun(s)   # try to parse...
            return result                    
        except Exception as e:  
            logging.debug('Exception for json loads: '+str(e))          
            if 'delimiter' in str(e):
                # E.g.: "Expecting , delimiter: line 34 column 54 (char 1158)"
                logging.debug('Escaping quote to fix.')
                s = escape_quote(s,e)
            elif 'escape' in str(e):
                # E.g.: "Invalid \escape: line 1 column 9 (char 9)"
                logging.debug('Removing invalid escape to fix.')
                s = remove_invalid_escape(s)
            else:
                break
    return json_fun('{}')

def remove_invalid_escape(value):
    # Inspired by https://stackoverflow.com/questions/19176024/how-to-escape-special-characters-in-building-a-json-string
    return re.sub(r'\\(?!["\\/bfnrt])', '', value)

def escape_quote(s,e):
    # Inspired by https://stackoverflow.com/questions/18514910/how-do-i-automatically-fix-an-invalid-json-string
    # "Expecting , delimiter: line 34 column 54 (char 1158)"
    # position of unexpected character after '"'
    unexp = int(re.findall(r'\(char (\d+)\)', str(e))[0])
    # position of unescaped '"' before that
    unesc = s.rfind(r'"', 0, unexp)
    s = s[:unesc] + r'\"' + s[unesc+1:]
    # position of corresponding closing '"' (+2 for inserted '\')
    closg = s.find(r'"', unesc + 2)
    if closg + 2 < len(s):
        print closg, len(s)
        s = s[:closg] + r'\"' + s[closg+1:]
    return s

【讨论】:

  • 哇,这确实是一个笨蛋。您能否最终确定导致问题的条目或导致“错误”JSON 的行?因为如果您对此没有任何改变,这可能值得在我们的问题跟踪器 (code.google.com/p/googleappengine/issues/list) 上提出问题
  • 不,我永远找不到错误 JSON 的来源。从 5 月 13 日到 15 日,它似乎一下子崩溃了。如果当时对 App Engine 进行了与数据库或 JSON 相关的代码更新,那可能值得一看。如果没有,可能是我的一个用户输入了一些我没有充分检查的数据,它只是似乎到处都坏了。
  • 作为云平台支持团队的一员,我对此有一些既得利益。我想确保如果这种情况发生在其他人身上,系统会捕捉到它。您是否设法获得实际“损坏”您的数据存储的输入?
  • 不幸的是,我不知道这一切是如何发生的。我只是注意到有一天我的应用程序没有响应,并且日志显示了所有这些错误消息。这些消息似乎来自数据库的不同部分,用于对应不同用户的数据。
  • 嗯....好吧。我会尝试深入研究,然后看看我能用它做什么。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多