GAE: Почему этот код вызывает сбой на сервере? - PullRequest
0 голосов
/ 15 июля 2010

Я использую SDK GAE 1.3.5 devserver с Python. Когда я раскомментирую эту строку кода, GAEUnit зависает при каждой попытке запустить мой набор тестов:

dep_arc_tail_q = db.GqlQuery("SELECT * FROM DependencyArcTail WHERE courses = :1", course)

#problem line
modelutils.applyToResultsOfQuery(lambda tails : modelutils.removeCourseFromTails(course, tails), dep_arc_tail_q)

Методы modelutils:

def applyToResultsOfQuery(func, q):
    results = q.fetch(1000)
    while results:
        func(results)
        results = q.fetch(1000)

def removeCourseFromTail(course, tail):
    # tail = DependencyArcTail.get(key_tail)
    if not course in tail.courses:
        return

    if len(tail.courses) == 1:
        DependencyArcTail.delete(tail)
        return

    tail.courses.remove(course)

def removeCourseFromTails(course, tails):
    ''' Removes `course` from a collection of `tails` '''
    removeThisCourseFromTail = functools.partial(removeCourseFromTail, course)
    map(removeThisCourseFromTail, tails)

Я не получаю никакого сбоя или отслеживания ... devserver просто полностью не отвечает.

В частности, другая функция также использует modelutils.applyToResultsOfQuery для удаления моделей:

def _deleteType(kind):
 q = kind.all(keys_only=True)
 deleteResultsOfQuery(q)

def deleteResultsOfQuery(q):
    applyToResultsOfQuery(db.delete, q)

Тесты работают нормально с этими методами, заставляя меня думать, что проблема не в applyToResultsOfQuery.

Вот используемые модели:

class Course(db.Model):
    dept_code = db.StringProperty(required=True)
    number = db.IntegerProperty(required=True)
    title = db.StringProperty(multiline=True) # not sure that this should be multiline...
    pickled_pre_reqs = db.StringProperty(multiline=True)

    # the unparsed pre req phrase (like "CS 2110 or 1110")
    unparsed_pre_reqs = db.StringProperty()

    # the full value of the Note part of the course catalog listing
    full_description = db.TextProperty()

    # the page on which this course is described
    course_catalog_url = db.LinkProperty()

    parse_succeeded = db.BooleanProperty()

    # true if this course has had its dependency graph built
    graph_built = db.BooleanProperty()

    tailsMemberOf = db.ListProperty(db.Key)

    def getPreReqs(self):
        return pickle.loads(str(self.pickled_pre_reqs))

    def __repr__(self):
        if self.dept_code == "UNKNOWN":
            return "Unknown course"

        return "%s %s: %s" % (self.dept_code, self.number, self.title)

    # just use __dict__?
    def __attrs(self):
        return (self.dept_code, self.number, self.title, self.pickled_pre_reqs, self.full_description, self.unparsed_pre_reqs, self.course_catalog_url)

    def __eq__(self, other):
        return isinstance(other, Course) and self.__attrs() == other.__attrs()

    def __hash__(self):
        return hash(self.__attrs())

class DependencyArcTail(db.Model):
    ''' A list of courses that is a pre-req for something else '''
    courses = db.ListProperty(db.Key) # can this be changed to Course.key?

    ''' a list of heads that reference this one '''
    forwardLinks = db.ListProperty(db.Key)

    def __repr__(self):
        return "DepArcTail %d: courses='%s' forwardLinks='%s'" % (id(self), getReprOfKeys(self.courses), getIdOfKeys(self.forwardLinks))

    def __eq__(self, other):
        return isinstance(other, DependencyArcTail) and set(self.courses) == set(other.courses) and set(self.forwardLinks) == set(other.forwardLinks)

    def __hash__(self):
        return hash((frozenset(self.courses), frozenset(self.forwardLinks)))

Что еще я могу здесь делать не так?

ОБНОВЛЕНИЕ : Похоже, что после запуска теста без этой строки происходит сбой всего сервера разработки. Если после этого я перейду на страницу без теста, я получу 500 '. Я не уверен, какие выводы из этого сделать.

ОБНОВЛЕНИЕ 2 : Если я избавлюсь от modeutils и напишу по-другому, он будет работать нормально:

dep_arc_tail_q = db.GqlQuery("SELECT * FROM DependencyArcTail WHERE courses = :1", course)
# modelutils.applyToResultsOfQuery(lambda tails : modelutils.removeCourseFromTails(course, tails), dep_arc_tail_q)
results = dep_arc_tail_q.fetch(1000)
# while results:
for tail in results:
    modelutils.removeCourseFromTail(course, tail)
    # results = dep_arc_tail_q.fetch(1000)

Однако, если я изменю комментарии вверх, они снова не получатся:

dep_arc_tail_q = db.GqlQuery("SELECT * FROM DependencyArcTail WHERE courses = :1", course)
# modelutils.applyToResultsOfQuery(lambda tails : modelutils.removeCourseFromTails(course, tails), dep_arc_tail_q)
results = dep_arc_tail_q.fetch(1000)
while results:
    for tail in results:
        modelutils.removeCourseFromTail(course, tail)
    results = dep_arc_tail_q.fetch(1000)

Я получаю бесконечный цикл? fetch() не работает, как я ожидаю?

1 Ответ

4 голосов
/ 15 июля 2010

fetch(1000) всегда будет возвращать первые 1000 результатов.

Вы можете попробовать использовать курсоры , что-то вроде этого:

results = dep_arc_tail_q.fetch(1000) 
while results: 
    for tail in results: 
        modelutils.removeCourseFromTail(course, tail) 
    results = dep_arc_tail_q.with_cursor(dep_arc_tail_q.cursor()).fetch(1000) 
...