воскресенье, 20 июля 2014 г.

Хранение сессии в базе данных

В список моих рабочих обязанностей входит поддержка одного из наших внутренних сервисов, написанного с использованием Yii Framework.

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

Причина - приличный набор данных, который в ней хранится. Дело в том, что при авторизации пользователя, в сессию сохраняются некоторые данные о нем, список его прав (RBAC) и прочие данные приложения (какие-то массивы, переменные и прочее).

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

Решено опробовать, тем более что делается это очень просто. В файл конфига в раздел components вставляем код:

     'session' => [
             'class' => 'system.web.CDbHttpSession',
             'connectionID' => 'db',
             'autoCreateSessionTable' => true, // default
     ],

Индекс по полю expired - рекомендация от разработчиков Yii, доступна по ссылке выше. Также нам рекомендуют после первого запуска установить параметр autoCreateSessionTable = false, чтобы отключить проверку существования таблицы.

Подключаю - улыбаюсь. Действительно, сессия теперь стартует практически моментально.
Почему так? Причины две:

  1. скорость чтения (чтение из базы быстрее чтения из файла)
  2. чтение из файла блокирует файл, пока не закончит с ним работать (если время чтения из файла при обработке запроса будет превышать время до следующего поступившего запроса, ему придется ждать завершения)
Если же вы активно используете кэширование, вам также подойдет класс CCacheHttpSession. Но здесь нужно быть осторожным, т.к. кэш может затираться раньше положенного времени. Как следствие - сессии будут внезапно обрываться.

P.S.
Чуть позже, на нашем основном проекте, тоже стали хранить сессии в базе данных из-за тормозов, связанных с увеличением количества пользователей и генерируемыми ими AJAX-запросами. Они используются у нас из JS по таймауту для актуализации контента на странице. Да, решение устаревшее и требует пересмотрения, но как временная мера компонент CDbHttpSession подошел идеально. После активации ресурс просто ожил.


воскресенье, 15 июня 2014 г.

Assembla шпаргалка

Этот пост - заметка, в первую очередь для себя самого, а также для сторонников SVN и пользователей сервиса Assembla.

Немного истории. Так сложилось, что первой системой контроля версий (Subversion) с которой я познакомился, была SVN с использованием клиента TortoiseSVN.

Поначалу разработка велась в локальном хранилище, которое находилось в папке, которая в свою очередь синхронизировалась с одним из облачных хранилищ. В моем случае это был Dropbox.

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

После некоторых поисков и перездов я остановился на сервисе https://www.assembla.com. Почему именно он? Не буду сейчас подробно описывать его достоинства/недостатки, возможно сделаю это в одном из следующих постов. Скажу просто - понравился! Ну и да, есть бесплатный тариф =)

Далее хочу привести список полезных команд, которые можно указывать в тексте описаний:
  • "re #<номер тикета>" - привязать коммит к тикету. Синонимы команды: "references", "refs" и "see".
  • "<статус> #<номер тикета>" - устанавливает указанный статус. Статус указывается из списка предусмотренных:  New, Accepted, Test, Fixed, Invalid.
  • "[[r:<номер ревизии>]]" - привязать коммит к тикету (после коммита, в описании тикета)


Это самые основные. В дальнейшем, думаю, список будет пополняться. Если вы находите полезными и используете какие-то еще команды или может используемый вами сервис превосходит описанный выше - пишите в комментариях. Буду рад обмену опытом!

среда, 9 апреля 2014 г.

Организация мультиязычности в приложении на Yii, часть 1


Мне очень нравится максимально автоматизировать код.
Иногда даже пара строк кода в нужном месте могут существенно сократить время разработки или облегчить его дальнейшую поддержку.

Я много пишу на Yii framework. В нем реализована очень удобная, на мой взгляд, система мультиязычности. Кто не использовал, настоятельно рекомендую ознакомиться и внедрять в свой проект на самом начальном этапе разработки. Сложно предсказать скорость развития проекта и время его выхода на международную аудиторию :)

Итак, по умолчанию сообщения проекта хранятся в директории messages/{ID языка}.
В своей практике я разбиваю папку языка messages/ru на поддиректории: controllers, models, widgets. Затем в них уже собираю файлы с сообщением. Имя файла соответствует имени контроллера/модели/виджета. Файл с общими фразами для всего приложения, по умолчанию app.php, оставляем в папке языка.

Ок, удобно, скажете вы, но ведь теперь нужно вместо
Yii::t("app", "Hello, world")

набирать еще более длинное выражение:
Yii::t("controllers/controller", "Hello, world")
Да, отвечу я вам, но пусть за нас это сделает машина.
Открываем файл app.php и меняем его содержимое с:
return [
     "message 1" => "сообщение 1",
     "message 2" => "сообщение 2",
     ...
     "message N" => "сообщение Н",
]
на следующее:
$controllerMessages = dirname(__FILE__).'/controllers/'.Yii::app()->controller->id.'.php';
return return CMap::mergeArray(
     [
          "message 1" => "сообщение 1",
          "message 2" => "сообщение 2",
          ...
          "message N" => "сообщение Н",
     ],
     (is_file($controllerMessages) ? require_once($controllerMessages) : [])
)
Теперь при вызове Yii::t('app', 'Hello world'), словарь сообщений для текущего контроллера подключится автоматически.

Как быть дальше с моделями и виджетами, я расскажу во второй части статьи.


вторник, 8 апреля 2014 г.

Изменение HTML-формы при отправлении.


Недавно столкнулся с одной задачкой.

В HTML-форме интернет магазина необходимо было сделать две submit кнопки.

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

Совсем забыв про основы и потеряв тележку времени, выбирая среди костыля с перехватом массива $_POST или написанием дополнительных методов класса контроллера, наткнулся на следующее решение:


Как выяснилось, кнопке с типом submit можно также присваивать атрибуты name и value. При отправлении, их значения заменят одноименные значения, объявленные в форме выше.

Вот так вот =)