Миграция с push-задач из очереди задач App Engine на облачные задачи (модуль 8)

1. Обзор

Серия курсов по кодированию Serverless Migration Station (практические руководства для самостоятельного обучения) и сопутствующие видеоролики призваны помочь бессерверным разработчикам Google Cloud модернизировать свои приложения, помогая им выполнить одну или несколько миграций, в первую очередь отходя от устаревших сервисов. Это сделает ваши приложения более портативными и предоставит вам больше возможностей и гибкости, позволяя интегрироваться с более широким спектром облачных продуктов и получать к ним доступ, а также упростить обновление до более новых языковых версий. Первоначально эта серия ориентирована на самых первых пользователей облака, в первую очередь на разработчиков App Engine (стандартной среды), но эта серия достаточно широка, чтобы включать в себя другие бессерверные платформы, такие как Cloud Functions и Cloud Run , или другие бессерверные платформы, если это применимо.

Цель этой лаборатории кода — показать разработчикам App Engine Python 2, как перейти от очереди задач App Engine (push-задачи) к облачным задачам. Также существует неявная миграция из App Engine NDB в Cloud NDB для доступа к хранилищу данных (в основном описанная в модуле 2).

Мы добавили использование задач push в модуле 7 и перенесли это использование в облачные задачи здесь, в модуле 8, а затем перешли к Python 3 и Cloud Datastore в модуле 9. Те, кто использует очереди задач для задач извлечения , перейдут в Cloud Pub/Sub. вместо этого следует обратиться к модулям 18–19.

Вы узнаете, как

Что вам понадобится

Опрос

Как вы будете использовать этот урок?

Только прочитай это Прочитайте его и выполните упражнения.

Как бы вы оценили свой опыт работы с Python?

Новичок Средний Опытный

Как бы вы оценили свой опыт использования сервисов Google Cloud?

Новичок Средний Опытный

2. Предыстория

Очередь задач App Engine поддерживает задачи как push, так и pull. Чтобы улучшить переносимость приложений, команда Google Cloud рекомендует перейти с устаревших комплексных служб, таких как очередь задач, на другие автономные облачные или сторонние эквивалентные службы.

Миграция задач по запросу рассматривается в модулях миграции 18–19, а модули 7–9 посвящены миграции задач по запросу. Чтобы перейти от push-задач App Engine Queue Task Queue, мы добавили его использование в существующий пример приложения Python 2 App Engine, которое регистрирует новые посещения страниц и отображает самые последние посещения. В модуль 7 добавлена ​​задача push для удаления самых старых посещений — они больше никогда не будут отображаться, так зачем же им занимать дополнительное место в хранилище данных? Эта лаборатория кода Модуля 8 сохраняет ту же функциональность, но переносит базовый механизм организации очередей из задач push Queue Task в Cloud Tasks, а также повторяет миграцию Модуля 2 из App Engine NDB в Cloud NDB для доступа к хранилищу данных.

Это руководство включает в себя следующие шаги:

  1. Настройка/Предварительная работа
  2. Обновить конфигурацию
  3. Изменить код приложения

3. Настройка/Предварительная работа

В этом разделе объясняется, как:

  1. Настройте свой облачный проект
  2. Получить базовый образец приложения
  3. (Повторное)развертывание и проверка базового приложения.
  4. Включите новые сервисы/API Google Cloud

Эти шаги гарантируют, что вы начнете с рабочего кода и что ваш пример приложения готов к миграции в облачные службы.

1. Проект установки

Если вы завершили лабораторную работу по Модулю 7 , повторно используйте тот же проект (и код). Альтернативно создайте новый проект или повторно используйте другой существующий проект. Убедитесь, что у проекта есть активный платежный аккаунт и включенное приложение App Engine. Найдите идентификатор своего проекта, так как он понадобится вам во время этой лабораторной работы, используя его всякий раз, когда вы встретите переменную PROJECT_ID .

2. Получите базовый образец приложения.

Одним из предварительных условий является работающее приложение App Engine Модуля 7: выполните лабораторную работу по Модулю 7 (рекомендуется) или скопируйте приложение Модуля 7 из репозитория. Независимо от того, используете ли вы свой или наш, мы начнем с кода Модуля 7 («СТАРТ»). Эта лаборатория кода проведет вас через миграцию, завершающуюся кодом, похожим на тот, что находится в папке репозитория Модуля 8 («FINISH»).

Независимо от того, какое приложение Модуля 7 вы используете, папка должна выглядеть так, как показано ниже, возможно, с папкой lib :

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

3. (Повторное) развертывание и проверка базового приложения.

Выполните следующие шаги для развертывания приложения Модуля 7:

  1. Удалите папку lib , если она есть, и запустите pip install -t lib -r requirements.txt чтобы повторно заполнить lib . Вместо этого вам может потребоваться использовать pip2 если на вашей машине разработки установлены Python 2 и 3.
  2. Убедитесь, что вы установили и инициализировали инструмент командной строки gcloud и проверили его использование .
  3. (Необязательно) Настройте свой облачный проект с помощью gcloud config set project PROJECT_ID если вы не хотите вводить PROJECT_ID с каждой командой gcloud , которую вы вводите.
  4. Разверните пример приложения с помощью gcloud app deploy
  5. Убедитесь, что приложение работает как положено и без проблем. Если вы завершили лабораторную работу по Модулю 7, приложение отображает самых популярных посетителей, а также самые последние посещения (показано ниже). Внизу указаны старые задачи, которые будут удалены.

4aa8a2cb5f527079.png

4. Включите новые сервисы/API Google Cloud.

В старом приложении использовались встроенные службы App Engine, которые не требуют дополнительной настройки, в отличие от автономных облачных служб, а в обновленном приложении будут использоваться как облачные задачи, так и облачное хранилище данных (через клиентскую библиотеку Cloud NDB). Ряд облачных продуктов имеют квоты уровня «Всегда бесплатно» , включая App Engine , Cloud Datastore и Cloud Tasks . Пока вы не выходите за эти пределы, с вас не должна взиматься плата за выполнение этого руководства. Облачные API можно включить либо из облачной консоли, либо из командной строки, в зависимости от ваших предпочтений.

Из облачной консоли

Перейдите на страницу библиотеки API-менеджера (для нужного проекта) в Cloud Console и найдите API-интерфейсы Cloud Datastore и Cloud Tasks, используя панель поиска в середине страницы:

c7a740304e9d35b.png

Нажмите кнопку «Включить» для каждого API отдельно — вам может быть предложено ввести платежную информацию. Это пример страницы библиотеки API Cloud Pub/Sub (не включайте API Pub/Sub для этой кодовой лаборатории, только облачные задачи и хранилище данных):

1b6c0a2a73124f6b.jpeg

Из командной строки

Хотя включение API из консоли визуально информативно, некоторые предпочитают командную строку. Введите команду gcloud services enable cloudtasks.googleapis.com datastore.googleapis.com чтобы включить оба API одновременно:

$ gcloud services enable cloudtasks.googleapis.com datastore.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Вам может быть предложено ввести платежную информацию. Если вы хотите включить другие облачные API и узнать, каковы их «URI», их можно найти внизу страницы библиотеки каждого API. Например, обратите внимание pubsub.googleapis.com как «Имя службы» внизу страницы Pub/Sub чуть выше.

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

4. Обновить конфигурацию

Обновления в конфигурации явно связаны с дополнительным использованием клиентских библиотек Cloud. Независимо от того, какие из них вы используете, те же изменения необходимо внести в приложения, которые не используют клиентские библиотеки Cloud.

требования.txt

Модуль 8 заменяет использование App Engine NDB и очереди задач из модуля 1 на Cloud NDB и Cloud Tasks. Добавьте google-cloud-ndb и google-cloud-tasks в requirements.txt , чтобы присоединиться flask из модуля 7:

flask
google-cloud-ndb
google-cloud-tasks

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

app.yaml

При использовании облачных клиентских библиотек среде выполнения Python 2 App Engine требуются определенные сторонние пакеты, а именно grpcio и setuptools . Пользователи Python 2 должны перечислить подобные встроенные библиотеки вместе с доступной версией или «последней» версией в app.yaml . Если у вас еще нет раздела libraries , создайте его и добавьте обе библиотеки следующим образом:

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest

При переносе вашего приложения в нем может уже быть раздел libraries . Если это так, и grpcio и setuptools отсутствуют, просто добавьте их в раздел существующих libraries . Обновленный app.yaml теперь должен выглядеть так:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest

appengine_config.py

Вызов google.appengine.ext.vendor.add() в appengine_config.py lib сторонние библиотеки, скопированные (иногда называемые «вендорными» или «самообъединенными»), к вашему приложению. Выше в app.yaml мы добавили встроенные сторонние библиотеки, и им требуется setuptools.pkg_resources.working_set.add_entry() чтобы связать ваше приложение со встроенными пакетами в lib . Ниже приведен исходный файл appengine_config.py Модуля 1 и после внесения обновлений Модуля 8:

ДО:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

ПОСЛЕ:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

Аналогичное описание также можно найти в документации по миграции App Engine .

5. Измените код приложения.

В этом разделе представлены обновления основного файла приложения main.py , заменяющие использование push-очередей очереди задач App Engine на облачные задачи. В веб-шаблоне templates/index.html изменений нет — оба приложения должны работать одинаково, отображая одни и те же данные. Изменения основного приложения разбиты на следующие четыре «задачи»:

  1. Обновление импорта и инициализации
  2. Обновление функциональности модели данных (Cloud NDB)
  3. Миграция на Cloud Tasks (и Cloud NDB)
  4. Обновить (push) обработчик задач

1. Обновите импорт и инициализацию.

  1. Замените App Engine NDB ( google.appengine.ext.ndb ) и Task Queue ( google.appengine.api.taskqueue ) на Cloud NDB ( google.cloud.ndb ) и Cloud Tasks ( google.cloud.tasks ) соответственно.
  2. Облачные клиентские библиотеки требуют инициализации и создания «API-клиентов»; назначьте их ds_client и ts_client соответственно.
  3. В документации по очереди задач указано: «App Engine предоставляет очередь push-уведомлений по умолчанию с именем default , которая настроена и готова к использованию с настройками по умолчанию». Cloud Tasks не предоставляет очередь default (поскольку это автономный облачный продукт, независимый от App Engine), поэтому для создания очереди Cloud Tasks с именем default требуется новый код.
  4. Очередь задач App Engine не требует указания региона, поскольку она использует регион, в котором работает ваше приложение. Однако, поскольку Cloud Tasks теперь является независимым продуктом, для него требуется регион, и этот регион должен соответствовать региону, в котором работает ваше приложение. Имя региона и идентификатор облачного проекта необходимы для создания «полного пути» в качестве уникального идентификатора очереди.

Обновления, описанные в третьем и четвертом пунктах выше, составляют основную часть необходимых дополнительных констант и инициализации. Посмотрите «до» и «после» ниже и внесите эти изменения в верхнюю часть main.py

ДО:

from datetime import datetime
import logging
import time
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb

app = Flask(__name__)

ПОСЛЕ:

from datetime import datetime
import json
import logging
import time
from flask import Flask, render_template, request
from google.cloud import ndb, tasks

app = Flask(__name__)
ds_client = ndb.Client()
ts_client = tasks.CloudTasksClient()

_, PROJECT_ID = google.auth.default()
REGION_ID = 'REGION_ID'    # replace w/your own
QUEUE_NAME = 'default'     # replace w/your own
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)

2. Обновление функциональности модели данных (Cloud NDB)

App Engine NDB и Cloud NDB работают практически одинаково. Никаких серьезных изменений ни в модели данных, ни в функции store_visit() не произошло. Единственное заметное отличие заключается в том, что создание сущности Visit в store_visit() теперь инкапсулируется внутри блока Python with . Cloud NDB требует, чтобы весь доступ к хранилищу данных контролировался в его контекстном менеджере, отсюда и оператор with . Фрагменты кода ниже иллюстрируют эту небольшую разницу при переходе на Cloud NDB. Внедрите это изменение.

ДО:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

ПОСЛЕ:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

3. Переход на Cloud Tasks (и Cloud NDB)

Наиболее критическое изменение в этой миграции меняет базовую инфраструктуру массового обслуживания. Это происходит в функции fetch_visits() , где создается (push) задача для удаления старых посещений и ставится в очередь для выполнения. Однако исходная функциональность Модуля 7 осталась нетронутой:

  1. Запрос последних посещений.
  2. Вместо немедленного возврата этих посещений сохраните временную метку последнего Visit (самого старого из отображаемых) — можно безопасно удалить все посещения, более ранние, чем это.
  3. Выделите временную метку в виде числа с плавающей запятой и строки с помощью стандартных утилит Python и используйте их в различных целях, например, отображение пользователю, добавление в журналы, передачу обработчику и т. д.
  4. Создайте задачу push с этой меткой времени в качестве полезной нагрузки и /trim в качестве URL-адреса.
  5. Обработчик задачи в конечном итоге вызывается через HTTP POST для этого URL-адреса.

Этот рабочий процесс иллюстрируется фрагментом кода «до»:

ДО:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    taskqueue.add(url='/trim', params={'oldest': oldest})
    return data, oldest_str

Хотя функциональность остается прежней, Cloud Tasks становится платформой выполнения. Обновления, влияющие на это изменение, включают:

  1. Оберните запрос Visit внутри with Python (повторяя миграцию модуля 2 в Cloud NDB)
  2. Создайте метаданные облачных задач, включая ожидаемые атрибуты, такие как полезные данные временной метки и URL-адрес, а также добавьте тип MIME и закодируйте полезные данные в формате JSON.
  3. Используйте клиент Cloud Tasks API, чтобы создать задачу с метаданными и полным именем очереди.

Эти изменения в fetch_visits() показаны ниже:

ПОСЛЕ:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    with ds_client.context():
        data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return data, oldest_str

4. Обновление (push) обработчика задач

Функция обработчика задач (push) не требует серьезных обновлений; оно требует только исполнения. Это применимо к очереди задач или облачным задачам. «Код есть код», как говорится. Однако есть небольшие изменения:

  1. Полезные данные временной метки дословно передавались в очередь задач, но для облачных задач они были закодированы в формате JSON и поэтому по прибытии должны быть проанализированы в формате JSON.
  2. Вызов HTTP POST для /trim с Task Queue имел неявный MIME-тип application/x-www-form-urlencoded , но в Cloud Tasks он явно обозначается как application/json , поэтому существует немного другой способ извлечения полезных данных.
  3. Используйте диспетчер контекста клиента Cloud NDB API (переход модуля 2 в Cloud NDB).

Ниже приведены фрагменты кода до и после внесения этих изменений в обработчик задач trim() :

ДО:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = request.form.get('oldest', type=float)
    keys = Visit.query(
            Visit.timestamp < datetime.fromtimestamp(oldest)
    ).fetch(keys_only=True)
    nkeys = len(keys)
    if nkeys:
        logging.info('Deleting %d entities: %s' % (
                nkeys, ', '.join(str(k.id()) for k in keys)))
        ndb.delete_multi(keys)
    else:
        logging.info('No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

ПОСЛЕ:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    with ds_client.context():
        keys = Visit.query(
                Visit.timestamp < datetime.fromtimestamp(oldest)
        ).fetch(keys_only=True)
        nkeys = len(keys)
        if nkeys:
            logging.info('Deleting %d entities: %s' % (
                    nkeys, ', '.join(str(k.id()) for k in keys)))
            ndb.delete_multi(keys)
        else:
            logging.info(
                    'No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

Нет обновлений ни для основного обработчика приложения root() , ни для веб-шаблона templates/index.html .

6. Подведение итогов/очистка

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

Развертывание и проверка приложения

Разверните свое приложение с помощью gcloud app deploy . Вывод должен быть идентичен приложению Модуля 7, но помните, что вы перешли на совершенно другой продукт push-очереди, что делает ваше приложение более портативным, чем раньше!

4aa8a2cb5f527079.png

Очистить

Общий

Если вы закончили, мы рекомендуем вам отключить приложение App Engine , чтобы избежать выставления счетов. Однако, если вы хотите протестировать или поэкспериментировать еще, на платформе App Engine предусмотрена бесплатная квота , поэтому, пока вы не превысите этот уровень использования, с вас не будет взиматься плата. Это касается вычислений, но за соответствующие службы App Engine также может взиматься плата, поэтому для получения дополнительной информации посетите страницу с ценами . Если эта миграция включает в себя другие облачные службы, они оплачиваются отдельно. В любом случае, если применимо, см. раздел «Специально для этой кодовой лаборатории» ниже.

Для полной информации: развертывание на бессерверной вычислительной платформе Google Cloud, такой как App Engine, требует незначительных затрат на сборку и хранение . Cloud Build имеет собственную бесплатную квоту, как и Cloud Storage . Хранение этого изображения использует часть этой квоты. Однако вы можете жить в регионе, где нет такого уровня бесплатного пользования, поэтому следите за использованием хранилища, чтобы минимизировать потенциальные затраты. Конкретные «папки» облачного хранилища, которые вам следует просмотреть, включают:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Ссылки на хранилище, указанные выше, зависят от вашего PROJECT_ID и * LOC *ации, например « us », если ваше приложение размещено в США.

С другой стороны, если вы не собираетесь продолжать работу с этим приложением или другими связанными с ним программами миграции и хотите полностью удалить все, закройте свой проект .

Специально для этой кодовой лаборатории

Перечисленные ниже услуги являются уникальными для этой лаборатории разработки. Дополнительную информацию см. в документации каждого продукта:

Следующие шаги

На этом завершается переход от push-задач App Engine Task Queue к облачным задачам. Если вы заинтересованы в продолжении переноса этого приложения на Python 3 и дальнейшем переходе на Cloud Datastore из Cloud NDB, рассмотрите Модуль 9 .

Cloud NDB существует специально для разработчиков App Engine на Python 2 и обеспечивает почти идентичный пользовательский интерфейс, но у Cloud Datastore есть собственная клиентская библиотека, созданная для пользователей, не являющихся пользователями App Engine, или новых пользователей App Engine (Python 3). Однако, поскольку Cloud NDB доступен для Python 2 и 3, переход на Cloud Datastore не требуется.

Cloud NDB и Cloud Datastore имеют доступ к Datastore (хотя и по-разному), поэтому единственная причина рассмотреть возможность перехода на Cloud Datastore — это если у вас уже есть другие приложения, особенно приложения, не относящиеся к App Engine, использующие Cloud Datastore и желание стандартизировать его на одном Клиентская библиотека хранилища данных. Эта необязательная миграция из Cloud NDB в Cloud Datastore также рассматривается отдельно (без очереди задач или облачных задач) в модуле 3 .

Помимо модулей 3, 8 и 9, следует рассмотреть и другие модули миграции, направленные на отказ от устаревших комплексных сервисов App Engine:

App Engine больше не является единственной бессерверной платформой в Google Cloud. Если у вас есть небольшое приложение App Engine или приложение с ограниченной функциональностью, и вы хотите превратить его в автономный микросервис, или вы хотите разбить монолитное приложение на несколько повторно используемых компонентов, это веские причины рассмотреть возможность перехода на облачные функции . Если контейнеризация стала частью вашего рабочего процесса разработки приложений, особенно если он состоит из конвейера CI/CD (непрерывная интеграция/непрерывная доставка или развертывание), рассмотрите возможность перехода на Cloud Run . Эти сценарии рассматриваются в следующих модулях:

  • Миграция с App Engine на облачные функции: см. Модуль 11.
  • Миграция с App Engine на Cloud Run: см. Модуль 4 , чтобы контейнеризировать приложение с помощью Docker, или Модуль 5 , чтобы сделать это без контейнеров, знаний Docker или Dockerfile s.

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

Независимо от того, какой модуль миграции вы рассматриваете следующим, весь контент Serverless Migration Station (лаборатории кода, видео, исходный код [при наличии]) можно получить в его репозитории с открытым исходным кодом . README репозитория также содержит рекомендации о том, какие миграции следует учитывать, а также любой соответствующий «порядок» модулей миграции.

7. Дополнительные ресурсы

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

Проблемы/отзывы Codelabs

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

Миграционные ресурсы

Ссылки на папки репозитория для Модуля 7 (НАЧАЛО) и Модуля 8 (ФИНИШ) можно найти в таблице ниже.

Кодлаб

Питон 2

Питон 3

Модуль 7

код

код (не представлен в этом руководстве)

Модуль 8 (это кодовая лаборатория)

код

(н/д)

Интернет-ресурсы

Ниже приведены онлайн-ресурсы, которые могут иметь отношение к этому руководству:

Очередь задач App Engine и облачные задачи

App Engine NDB и Cloud NDB (хранилище данных)

Платформа App Engine

Другая информация об облаке

Видео

Лицензия

Эта работа распространяется под лицензией Creative Commons Attribution 2.0 Generic License.