вторник, июля 20, 2010

Тестирование сервлетов и Task Queue в GAE (с guice ServletModule).

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

Но бывает так что с тестами действительно сильно упрощается и ускоряется процесс разработки даже небольших проектов. Например как раз сейчас делаю проектик на GAE (Google App Engine) который достаточно сложный. Много cron-задач создающих task'и (здесь и далее имеются в виду task'и из Task Queue), которые в свою очередь сами могут порождать task'и. Так как cron и Task Queues на девелоперском сервере поддерживаются довольно-таки условно - возникли неудобства с проверкой работоспособности.

Учитывая что в GAE есть всё для удобного локального тестирования (здесь) было решено позапускать нужные cron-задачи и task'и в нужной последовательности в тесте и там же проверить результат. Очевидно это быстрее чем руками в девелопмент сервере запускать cron-задачи и руками же проверять результат. Более того - так как это тест, то нет нужды потом зачищать datastore чтобы попробовать запустить то же самое, но с другими параметрами. Вобщем экономия времени была ощутимой, не говоря уже о том что куда приятнее откинуться на спинку кресла и смотреть за прогрессом, чем руками рефрешить сервлеты.

Запустить сервлет в тесте не так уж и сложно - я использовал httpunit. Те кто используют обычные сервлеты могут использовать его. У меня же возникла проблема, все мои cron/task-сервлеты были guice'фицированы и поэтому подход с httpunit не годился.

Немного подумав я решил что достаточно будет написать mock's для HttpServletRequest и HttpServletResponse и использовать полученный с помощью guice объект сервлета чтобы всё это заработало. В итоге всё что получилось я выложил сюда: http://code.google.com/p/gaelocaltest/. Там же есть пример использования на главной странице.

Конечно оно сделано весьма быстро на коленке и имеет ряд ограничений, но работает и вполне покрывает типовые задачи. Собственно кода там мало и он примитивен - так что желающие могут взять его за базу для своих целей если вдруг возможностей этого не хватит. Для тех кто не сталкивался с граблями по конфигурации для Local unit testing'а GAE, советую взглянуть на пример конфига.

Вобщем это решение сэкономило мне просто уйму времени. Может быть кому пригодится.

P.S. Для проектов имеющих посещаемость 1.5 человека в сутки и не имеющих постоянно "молотящих" cron/task сервлетов использование guice приведёт к частому появлению паузы при открытии сайта, так как из-за guice увеличится время старта. Сейчас правда все вроде лучше чем год назад - но народ периодически жалуется на эту багофичу GAE. Так что для таких проектов наверное не следует бежать внедрять guice - проще модифицировать мой код под httpunit (самому мне лень).

понедельник, мая 17, 2010

Удалить индекс в GAE для Java проекта

Для тех кто мучается с этой задачей, вот решение из гуглогруп:

1) скачайте GAE python sdk
2) в вашем java проекте создайте файл app.yaml с таким содержимым:

application: YOURJAVA_APPID
version: 1
runtime: python
api_version: 1

handlers:
- url: .*
script: main.py

3) из директории вашего java проекте запустите (предполагается appcfg.py прописан в PATH)
appcfg.py vacuum_indexes .

4) удалите индексы которые хотите удалить

5) удалите файл app.yaml

6) зазвездите здесь чтобы не приходилось так извращаться: http://code.google.com/p/googleappengine/issues/detail?id=1893

P.S. А вообще это какой-то позор и дискриминация.

четверг, апреля 29, 2010

Быстрый способ обработать большой набор данных

Довольно стандартная минизадача - взять данные из одного или нескольких источников, сгруппировать и как-либо обработать их и выдать на выход в неком формате. Часто для группировки/обработки сильно помогает наличие SQL базы данных. Для минизадач напрашивается sqlite (для явы я использую http://www.xerial.org/trac/Xerial/wiki/SQLiteJDBC но и вариант zentus вроде бы тоже использовал раньше). При больших объёмах данных узким местом обычно становится время затрачиваемое на insert/update. И тут сильно помогает то что в sqlite есть memory режим (имя базы данных для задания в конекте :memory:), что сильно ускоряет insert/update операции. Вобщем разница видна на глаз уже где-то на наборе из 500К объектов, а при отладке экономия времени просто неимоверная.

четверг, апреля 01, 2010

Про DTO в GAE+GWT

Не знаю как остальных, а меня всегда раздражала необходимость создавать DTO (Data transfer object) в связке GWT-GAE. Ну не то чтобы раздражала, но не приводила в восторг необходимость клепать одно и то же каждый раз когда в клиентскую часть надо отдать данные объекта.

Также всегда было ощущение что используя JDO, я уподобляюсь человеку забивающему гвозди микроскопом (вобщем понятно что какие-то экстра расходы на JDO уходят).

Так что если у кого-то были схожие ощущения делюсь ссылкой: objectify-appengine. Из плюсов - не нужны DTO(конечно при использовании GWT-safe библиотек), быстрый холодный старт и тп. Сам пока в бою не щупал - пока только в планах. Даже есть проектик подходящий.

воскресенье, февраля 21, 2010

Java сообщества

Подписался на некоторые java рассылки/сообщества. Поражен количеством людей не понимающих как оно работает и способных рассуждать только на уровне оберток/фреймворков. Интересно есть термин для программиста способного механически писать только в любимом фрейморке и не понимающего сути?

воскресенье, февраля 14, 2010

Про будущее вёрстки

Не прошло и года, как подвернулся случай изучить "GWT 2.0 Layout system". Случай подвернулся после того как в очередном проектике IE успешно не смог ничего показать, хотя ничего сложного от него не требовалось. В общем впечатления от "standards mode" пока сугубо положительные. Я как человек верстающий крайне редко, всегда убивал много времени на несложные вещи типа хедер с двумя колонками, правая резиновая и тп. Теперь куча проблем решена за меня практически из коробки: http://code.google.com/webtoolkit/doc/latest/DevGuideUiPanels.html . Задействование мозга конечно никто не отменял, но в целом многое упростилось и про хрень типа "а под IE мы напишем хак" в светлом будущем видимо можно будет забыть (да и сейчас при переходе на gwt layout'ы мой проектик мгновенно заработал в IE). Вобщем такими темпами скоро потребность в волшебных верстальщиках для проектов на GWT отпадёт.

Кстати если кто не был на GDD09(как например я), то тут есть записи: http://code.google.com/intl/ru/events/developerday/2009/sessions.html. Пробежавшись по заголовкам я просмотрел "GWT App Architecture Best Practices". В принципе сейчас это и в хелпе есть частично (про MVP), но всё равно советую посмотреть. На русском смотреть не советую - переводчик жжот местами. Жаль не было этой презентации года 3 назад, когда я городил похожее сам и собирал все шишки тоже сам (например злоупотреблял шиной для посыла всего и получал дикую прожорливость и тормознутость из-за этого - тут же докладчик сразу говорит что так делать не стоит, что сбережёт многим много нервных клеток). Правда на практике не всё так гладко как он рассказывает получается с MVP, но для ознакомления с концепцией в принципе и этого примера вполне достаточно чтобы загрузить средний мозг. А все сложности можно решить - главное понимать идею.

вторник, февраля 09, 2010

Лучший способ убить GAE

Если вдруг у вас в логах появились сплошные сообщения "Request was aborted after waiting too long to attempt to service your request. Most likely, this indicates that you have reached your simultaneous dynamic request limit. This is almost always due to excessively high latency in your app. Please see http://code.google.com/appengine/docs/quotas.html for more details." и вы недавно задеплоили новую версию, то не стоит первым делом проклинать гугл который не даёт вам по крону запускать относительно лёгкий на ваш взгляд скрипт. Потому что заподозрив гугл в плохом я стал искать признаки того что моя jvm постоянно релоадится из-за того что на сайт нету нагрузки извне и заниматься прочими глупостями. А всё оказалось очень просто. Относительно несложный regex натравленный на пару килобайт текста сжирал весь процессор в одну харю ну а дальше по цепочке не хватало процессора всем бэкграундным скриптам (которые впрочем успевали переодически пробиваться и худо-бедно работать). Самое хреновое что при этом почему-то и логгинг не работал(те чекпойнты заботливо прописанные по скрипту тупо ничего не писали в лог, а писалось только сообщение которое я привел выше), так что выделив методом исключения фрагмент кода на котором GAE ложился пришлось тупо догадаться в чём дело. :)

воскресенье, февраля 07, 2010

GAE как сделать rollback в java

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

Вобщем наконец я смог сломать своё приложение до состояния когда пришлось пользоваться консолью. Во время очередного деплоймента мне показалось что оно зависло и я отменил его и перезапустил eclipse. В итоге стал получать сообщение вида: "Another transaction by user *** is already in progress for this app and major version. That user can undo the transaction with appcfg.py's "rollback" command.". Вобщем пришлось лезть к консольным GAE тулзам в eclipse (*path to eclipse*)/plugins/com.google.appengine.eclipse.sdkbundle_VERSION/appengine-java-sdk/bin/ и там запустить (вариант для винды) appcfg.cmd -e vasyapupkin@gmail.com rollback <путь к war директории проекта eclipse>.

Также попробовал GAE "Task Queues". На мой взгляд замечательная вещь, очень удобно по сравнению со стандартными велосипедами на кроне. Жаль пока это экспериментальная фича и повально использовать даже в своём тестовом проектике я не буду пока.

Из новых обнаруженных небольших недостатков GAE:
- сторадж не очень стабилен, т.е. ситуации когда что-то не удаляется или не добавляется не так уж редки, что для серьёзных задач наверное сильно добавит гемороя;
- в java невозможно удалить неиспользуемые индексы (в гуглогруппах советуют сделать это из питоновского sdk), это ни на что не влияет но раздражает :).