Схема миграции на хранилище данных GAE - PullRequest
6 голосов
/ 28 февраля 2011

Во-первых, это мой первый пост о переполнении стека, поэтому, пожалуйста, прости меня за любые ошибки новичка. Если я могу уточнить, как сформулировать свой вопрос, пожалуйста, дайте мне знать.

Я запускаю большое приложение в Google App Engine и добавляю новые функции, которые вынуждают меня изменять старые классы данных и добавлять новые. Чтобы очистить нашу базу данных и обновить старые записи, я пытался написать сценарий, который может перебирать экземпляры класса, вносить изменения, а затем повторно сохранять их. Проблема заключается в том, что Google App Engine блокирует время, когда вы совершаете звонки на сервер, которые занимают больше нескольких секунд.

Я боролся с этой проблемой уже несколько недель. Лучшее решение, которое я нашел, здесь: http://code.google.com/p/rietveld/source/browse/trunk/update_entities.py?spec=svn427&r=427

Я создал версию этого кода для своего собственного сайта, которую вы можете увидеть здесь:

def schema_migration (self, target, batch_size=1000):
    last_key = None
    calls = {"Affiliate": Affiliate, "IPN": IPN, "Mail": Mail, "Payment": Payment, "Promotion": Promotion}

    while True:
        q = calls[target].all()
        if last_key:
            q.filter('__key__ >', last_key)
        q.order('__key__')
        this_batch_size = batch_size

        while True:
            try:
                batch = q.fetch(this_batch_size)
                break
            except (db.Timeout, DeadlineExceededError):
                logging.warn("Query timed out, retrying")
                if this_batch_size == 1:
                    logging.critical("Unable to update entities, aborting")
                    return
                this_batch_size //= 2

        if not batch:
            break

        keys = None
        while not keys:
            try:
                keys = db.put(batch)
            except db.Timeout:
                logging.warn("Put timed out, retrying")

        last_key = keys[-1]
        print "Updated %d records" % (len(keys),)

Как ни странно, код отлично работает для классов с числом экземпляров от 100 до 1000, и сценарий часто занимает около 10 секунд. Но когда я пытаюсь запустить код для классов в нашей базе данных с более чем 100K экземплярами, сценарий запускается в течение 30 секунд, а затем я получаю следующее:

"Ошибка: ошибка сервера

Сервер обнаружил ошибку и не смог выполнить ваш запрос. Если проблема сохраняется, сообщите о своей проблеме и укажите это сообщение об ошибке и запрос, вызвавший ее. ""

Есть идеи, почему GAE истекает через тридцать секунд? Что я могу сделать, чтобы обойти эту проблему?

Спасибо тебе! Keller

Ответы [ 2 ]

5 голосов
/ 28 февраля 2011

вы попадаете во вторую DeadlineExceededError по его звуку.Запросы AppEngine могут выполняться только в течение 30 секунд каждый.Когда вызывается DeadLineExceedError, ваша задача - прекратить обработку и привести в порядок, так как у вас заканчивается время, в следующий раз, когда оно будет поднято, вы не сможете его перехватить.1004 * чтобы разделить миграцию на пакеты и запустить каждый пакет с помощью очереди задач.

2 голосов
/ 28 февраля 2011

Началом вашего решения будет переход на использование очередей задач GAE. Эта функция позволит вам поставить еще одну работу в очередь позже.

Это на самом деле не решит проблему немедленно, потому что даже очереди задач ограничены короткими временными интервалами. Тем не менее, вы можете развернуть цикл, чтобы одновременно обрабатывать несколько строк в вашей базе данных. После завершения каждого пакета он может проверить, как долго он работал, и, если он был достаточно длинным, он может запустить новую задачу в очереди, чтобы продолжить, где текущая задача прекратится.

Альтернативное решение состоит в том, чтобы не переносить данные. Измените логику реализации, чтобы каждый объект знал, был ли он перенесен. Вновь созданные объекты или старые объекты, которые обновляются, будут иметь новый формат. Поскольку GAE не требует, чтобы у сущностей были все одинаковые поля, вы можете легко это сделать, если в реляционной базе данных это не практично.

...