Google App Engine

индекс
72,70

Разработка для Google AppEngine: с самого начала

Недавно я задал вопрос — было бы интересно хабралюдям почитать о том, как писать под Google AppEngine? Хабралюди сказали что да, интересно — ну я и решил начать. В этой статье мы рассмотрим следующие вопросы:
  1. Ультра-краткое введение в Google AppEngine (GAE), что это такое и с чем его едят
  2. Возможности и ограничения GAE
  3. Супер-краткий обзор архитектуры GAE-приложения
  4. Разработка минимального приложения с аутентификацией
  5. Разработка более сложного, реального приложения на основе MyTwiLinks
Начнем с самого начала, с самого простого — совсем для нубов (каковым я и являлся, когда начал разбираться с GAE), постепенно продвигаясь к более сложным концепциям, заканчивая грязными хаками на тему «как быть, если нельзя, но очень надо» (почти наверняка не успеем в рамках этого поста, но доберемся обязательно).



Что такое Google AppEngine?


Если верить официальныму Getting Started, GAE — это инфраструктура, которая позволяет выполнять ваши веб-приложения на серверах Google. GAE решает очень многие стандартные задачи веб-разработки, такие как:
  1. Организация хранилища данных и поиска к ним — не совсем SQL, но похоже.
  2. Возможность абсолютно прозрачного расширения в случае увеличения нагрузки — правильно разработанное приложение должно масштабироваться вообще без какого-то участия со стороны пользователя
  3. Авторизация пользователей через Google Authentication — задача решается в две строчки ровно.
  4. Управление очередями задач и старт задач по расписанию.
GAE позволяет использовать два языка — Python и Java. В этой статье мы сосредоточимся на Python, как более простом и прозрачным для GAE.

Особенности разработки под GAE


Есть несколько важных особенностей, которые нужно учитывать — они отличают среду GAE от других веб-фреймворков (строго говоря, GAE фреймворком и не является — это целая инфраструктура).
  1. До других компьютеров в сети можно достучаться только и исключительно по HTTP(s). Верно и обратное — приложения работающие на GAE доступны только по HTTP(s) и только по стандартным портам.
  2. Нет write-доступа к файловой системе. Максимум, что может делать приложение — это читать файлы, которые были загружены вместе с самим приложением. Для организации хранения данных следует использовать либо GAE Datastore (про это потом), либо memcache.
  3. Есть всего три сценария работы приложения:
    • Ответ на HTTP(s) запрос, в частном случае — запрос пользователя
    • Запуск задач по расписанию (cron)
    • Очередь задач.
    Важно отметить, что два последних типа являются под-типами первого — любая задача запускается как HTTP запрос по определенному адресу, разница лишь в том, кто его запускает — пользователь, менеджер очереди задач или cron. Длительность работы одной задачи не должна превышать 30 секунд — тоже немаловажное ограничение, и с ним приходится жить.

Вышенаписанное — ультра-краткий курс очень молодого бойца GAE, дальше мы ринемся в бой и там, по ходу, разберемся.

Создаем GAE-приложение


Чтобы максимально упростить жизнь простых разработчиков, компания Google выпустила небольшое приложение, которое называется Google AppEngine Launcher — оно позволяет создавать приложения локально и запускать их на локальной машине пользователя. Если вы используете Мак (так же как и очень многие google'ры) то для вас есть красивый GUI, для Linux'а есть набор консольных скриптов, простых до крайности.


Изначально я обещал рассказать про то, как был сделан MyTwiLinks, но потом понял, что без базовых знаний это будет довольно сложно. Поэтому начнем с чего-нибудь простого, например…



Приложение создано. Теперь мы можем сделать, в общем, две вещи: запустить его и посмотреть что же там было создано? Пожалуй, запустим. Нажимаем кнопочку «Run», и когда станет доступной — Browse:


Ничего, в общем, удивительного — все как и ожидалось. Теперь же пришла пора посмотреть, как это все устроено. Для удобства я рекомендую в настройках GAE Launcher указать ваш редактор:


Я рекомендую TextMate, как наиболее продвинутый и расширяемый, в вашем случае это может быть что-то другое. Нажимаем кнопочку Edit (выбрав наше созданное приложение) и получаем…



Минимальный GAE проект — три файла. Прямо сейчас нас интересуют даже два — app.yaml и main.py, так как index.yaml генерируется автоматически. Начнем с app.yaml:

	application: helloworld
	version: 1
	runtime: python
	api_version: 1
	handlers:
	- url: .*
	  script: main.py

Что вообще этот файл говорит?
  1. application — как не трудно догадаться, это — название приложения, именно так оно и будет известно GAE (и именно это имя будет использоваться для загрузки на сервера Google)
  2. version — GAE поддерживает очень гибкий механизм работы с версиями; одновременно может быть загружено (и работать!) значительное количество версий кода (при этом только одна из них является default)
  3. api_version — на данный момент — константа, должна быть “1”
  4. handlers — и вот тут-то и начинается все интересное. В этой секции мы перечисляем все URL, на которые приложение должно “отзываться” и скрипты, которые будут обрабатывать эти запросы. Url .* — “все остальное”, он всегда должен идти последним в списке.

Попробуем реализовать предельно простое приложение — для всех пользователей, которые будут заходить на страничку оно будет предлагать авторизоваться через Google, и записывать всех, кто был авторизован; администратору же оно будет позволять просматривать список пользователей, которые туда заходили. Начнем с авторизации.

	#!/usr/bin/env python

	from google.appengine.ext import webapp
	from google.appengine.ext.webapp import util

	from google.appengine.api import users

	class MainHandler(webapp.RequestHandler):

	  def get(self):
	       user = users.get_current_user()
	       if not user:
	           resp = ("Welcome to HelloWorld — please <a href='%s'>authorise</a> to continue" 
	                      % users.create_login_url("/"))
	       else:
	           resp = "Dear %s, thanks for authorising!" % user.nickname()

	       self.response.out.write(resp)

	def main():
	  application = webapp.WSGIApplication([('/', MainHandler)],
	                                       debug=True)
	  util.run_wsgi_app(application)


	if __name__ == '__main__':
	  main()


Хорошо, это не две строчки, которые я обещал — но согласитесь, большая часть была все же потрачена на «красивости» вроде общения с пользователем. Два выражения, которые действительно имеют значение, это user = users.get_current_user() и users.create_login_url("/"). Первая проверяет, есть ли у нас активная пользовательская сессия. Вторая же создает URL который приведет пользователя на форму авторизации, и в случае успеха — обратно на приложение (единственный параметр функции create_login_url). И что же у нас получилось?

Выводим форму запроса:


Форма авторизации — генерируется GAE автоматически; если приложение запускается на серверах Google, то вместо этого вы увидете стандартную форму «Sign in with your Google Account»:


И, наконец, результат:


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

Итого


Вот вам первая статья. Мои изначальные прогнозы, что все можно будет уместить легко и просто в один пост, оказались несколько оптимистичными — и так уже получилось довольно много, а мы только коснулись собственно написания кода. В следующей статье (которая, как я думаю, будет написана скоро — если хабралюдям будет это интересно) мы закончим наше приложение, разберемся, как хранить данные и как достучаться до них, и загрузим его на сервера Google. Созданный проект доступен здесь — будем дорабатывать его по ходу.

Update: Вторая часть — habrahabr.ru/blogs/gae/81920/
Update 2: Третья часть — habrahabr.ru/blogs/gae/81933/

Список рекомендуемой литературы будет состоять из одной ссылки: App Engine Python Overview — прочитайте, посмотрите, разберитесь. Мне этой документации хватило, хотя какое-то время это и заняло. Будут вопросы — спрашивайте, и, конечно, жду ваших отзывов и пожеланий к продолжению.
+60
25 января 2010, 13:39
130

комментарии (36)

0
Ag47 #
Меня такой вопрос интересует: есть app.yaml в который мы прописываем связку скриптов обработки и юрлов, так вот так вроде же в параметрах юрлов есть такой пункт: доступ только авторизованным или что-то подобное.
На основе этого в принципе логично, кидать на страницу авторизации(отдельную прописанную в том же app.yaml, а не самому проверять авторизован ли пользователь).

Так как же всё-таки лучше делать эту самую авторизацию?
0
sigizmund #
Все будет во второй части ;-) Часто бывает удобно показать одну страничку незалогиненным пользователям (и search engine-ботам) и другую — залогиненным, по одному и тому же адресу. Спасибо за комментарий!
0
Ag47 #
Ну если есть такая надобность, то да… но ведь код проверки вставлять на каждую такую страницу не тру
+проверка авторизации на разных уровнях (app.yaml и в коде), то же как-то не очень

В общем всё это вносит какую-то неразбериху=)
0
sigizmund #
Такой подход разумно использовать на главной странице, которая должна быть проиндексирована поисковиками и должна показывать что-то вменяемое, чтобы пользователь знал, зачем ему вообще туда логиниться. Остальные — да, вполне могут и должны использовать login: required
+2
Barmaleikin #
Большое спасибо за доступное введение. Я давно слышу про AppEngine, но поскольку эта область достаточно далека от сферы моей работы, никак не мог понять что же это такое. Все описания, что мне попадались, начинались с того насколько всё круто и просто в сравнении с другими системами, что мне совершенно ничего не говорило :) А тут все по делу и изложено более-менее просто и понятно. Продолжайте, буду ждать.
+4
sigizmund #
Спасибо, продолжение пишется!
0
rudenkovk #
Только начинаю знакомиться с GAE.
Как я понимаю, авторизация только с юзерами вида @gmail.com… или можно делать свою базу на основе стандартных средств?
0
sigizmund #
Не только @gmail.com — пользователи Google Apps тоже поддерживаются (например, я могу логиниться используя sigizmund[at]sigizmund.com). Можно сделать свой логин, я полагаю — но сложнее.
0
rudenkovk #
sigizmund.com — домен припаркован где-то у тебя на дедике(хостинг провадере) или прицеплен к гуглмейлу?
0
sigizmund #
Ээ с ним все сложно. DNS у него от GoDaddy, A-запись идет на sigizmund.posterous.com, а MX и SRV-записи показывают на Google Apps.
+1
rudenkovk #
Понял. Пока только это останавливает…
0
spe #
Свою систему авторизации сделать не проблема, та, что на нашем портале (ссылка в профиле, если интересно), разрабатывалась быстро, и в общем сам процесс разработки системы авторизации никак качественно не отличается от общепринятого — таблица в базе, куки, сессии…
+1
YK115 #
На сайте пишут www.arhimir.ru/main/ пишут:
Traceback (most recent call last):
File "/base/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 507, in __call__
handler.get(*groups)
File "/base/data/home/apps/ru-dev/15.339417036075904778/main_page_handler.py", line 88, in get
'arhs': at.get_top()
File "/base/data/home/apps/ru-dev/15.339417036075904778/tools/arch_top.py", line 17, in get_top
objects = DBGalleryObject.get_by_id(o_list)
File "/base/python_lib/versions/1/google/appengine/ext/db/__init__.py", line 999, in get_by_id
return get(keys)
File "/base/python_lib/versions/1/google/appengine/ext/db/__init__.py", line 1182, in get
entities = datastore.Get(keys)
File "/base/python_lib/versions/1/google/appengine/api/datastore.py", line 257, in Get
raise _ToDatastoreError(err)
Timeout


Можно прокомментировать данные ошибки в разрезе работы с GAE?
0
spe #
Можно. Сейчас идет работа связанная со сменой логики кэширования информации на главной странице, поэтому периодически вылезают таймауты. Примерно один раз в 2-3 часа. В общем баг скорее носит логический характер, GAP тут ни при чем
0
hellraiser09 #
а можно исходники проектов заливать на Github/Google Code?
0
sigizmund #
Можно, потом залью на Google Code (пока там заливать нечего было, но начиная со второй части все будет там).
0
velial #
спасибо за статью, как раз хотел начать разбираться с GAE
очень хотелось бы видеть в Ваших статьях, как можно хранить данные
0
sigizmund #
увидите ;-) код уже написан, осталось текст по-русски написать (с этим сложнее)
0
velial #
очень надеюсь

а можно обнаглеть и попросить еще пример AJAX под GAE?
он чем-то отличается в реализации, может есть свои подводные камни?

спрашиваю, т.к. хочу писать новый проект под ExtJS
и меня очень тревожит как быть с AJAX?
0
sigizmund #
Попросить можно, но не обязательно вы это получите ;-) Я очень слабо разбираюсь в веб-технологиях — предельно (беспредельно) далек от этой области; если получится — то напишу. Но лично я никаких подводных камней в принципе не вижу.
0
spe #
Никаких подводных камней, в общем-то нет. Внутри питонского GAP зашита обычное Django, которое через встроенные адаптеры работает с гугловской БД BigTable. С точки зрения аякса за год разработки я ни разу не столкнулся с какими-то координальными отличиями от разработки на обычном Django-хостинге.
0
velial #
в том то и дело, что с Django не работал
все время на php
+2
sigizmund #
а там все просто и клево — Питон же, понятнее чем PHP и гораздо логичнее. Я тоже с джангой не работал до GAE, а теперь начну.
+3
velial #
Тоже очень хочется уйти от пхп
0
rgaliull #
ведь речь идет о GWT?
0
sigizmund #
Честно говоря, на связке GWT+GAE я пасанул — точнее, не было достаточно сильного мотиватора ;-) но надеюсь, что кто-то эстафету подхватит.
+1
spe #
На недавнем московском Google Developer Day обещали в скором времени увеличить временную квоту обработки скрипта с 30 секунд.

Насчет среды разработки — почему вы не используется Eclipse'овский Pydev? Гораздо удобнее. Более того, последние версии Пайдева напрямую поддерживают работу с ГАП, к примеру можно заливать файлы на Гугл прямо из Эклипса.
0
sigizmund #
Ну да, можно, для MyTwiLinks я сперва даже использовал его… но привык я как-то к TextMate. К тому же для языков с динамической типизацией примерно в 70% случаев code completion не работает потому что он не может работать по определнию потому что тип объекта неизвестен — что сильно нивелирует ценности IDE в принципе.
0
dug #
О, а поиск полнотекстовый не обещали?
0
spe #
Нет, такого не припоминаю
0
mrskam #
Да, обещали и делают. Уже месяца 3-4 работают над этим. Issue 217 висит в Started. Подробности там в комментах от Max.Ross.
+1
sigizmund #
groups.google.com/group/google-appengine/browse_thread/thread/f64eacbd31629668/8dac5499bd58a6b7?lnk=gst&q=searchablemodel&pli=1

я его в MyTwiLinks использовал, но работает крайне нестабильно.
0
CONSTantius #
Это ведь практически перевод гугловского Getting Started, не так ли?
0
sigizmund #
Неа, читайте дальше.
+1
feodus #
Сначала обрадовался, т.к. мне очень интересна эта тема. Но только с точки зрения Java.
Поэтому когда увидел упоминание Питона все закрыл… ;-(

Жаль нет нормального Java ориентированного описания GAE.
0
sigizmund #
Ну с моей точки зрения, язык вообще не имеет значения. Просто на Питоне примеры получаются короче; с другой стороны, человеку с мало-мальским опытом не составит труда применить всю эту информацию к GAE/J.

Для Java писать не буду — там все точно так же, только кода бесполезного больше. Читайте code.google.com/appengine/docs/java/overview.html

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.