Recently in Catalyst Category

Тестинг Catalyst::Plugin::Session::Store::DBI

Как известно, этот модуль хранит сессии в текстовых полях в base64(nfreeze($data)), что является явно избыточным, т.к. можно юзать только Storable и blob для хранения. Поэтому - небольшой тестик:

nfreeze: time: 331 sec; speed: 3021 req/sec
thaw:    time: 213 sec; speed: 4694 req/sec
encode_base64: time: 67 sec; speed: 14925 req/sec
decode_base64: time: 116 sec; speed: 8620 req/sec
STORE: time: 399 sec; speed: 2506 req/sec
GET:   time: 328 sec; speed: 3048 req/sec

В тесте разложены методы MIME::Base64 и Storable, а также - всё вместе.

Как видно, производительность base64 явно избыточна, т.ч. в большинстве случаев можно не париться по этому поводу.

t_sess.txt

$c->forward() возвращает истину

$c->forward() возвращает только истину. Истину в последней инстанции :)

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

Массивы и хеши тоже нельзя возвращать. Т.к. получите последний элемент массива. Ссылки на них - пожалуйста. Ибо ссылка на массив истинна, даже если массив пустой.

Вот собственно и всё :) Теперь чуток примерчиков для наглядности:

sub t_zero   { 0           };
sub t_empty  { ""          };
sub t_undef  { undef       };
sub t_arr    { qw/a b c/   };
sub t_scalar { "ok"        };
sub t_arref  { [qw/a b c/] };
sub t_hashref{ {}          };

sub test {
    my ( $self, $c ) = @_;
    $c->forward('t_zero');    # 0
    $c->forward('t_empty');   # 0
    $c->forward('t_undef');   # 0
    $c->forward('t_arr');     # 'c'
    $c->forward('t_scalar');  # 'ok'
    $c->forward('t_arref');   # ['a', 'b', 'c']
    $c->forward('t_hashref'); # {}
};

Механизм

Как известно, механизм сессий построен по принципу frontend/backend. За фронтенд отвечает Session::State, за бэкенд - Session::Store. Первый работает с пользователем - передает и принимает айди сессии (например, в урле или куке). Второй - на стороне сервера. Он отвечает за хранение данных сессии.

В качестве фронтенда выберем State::Cookie (больше нечего, не в урлах же сессии передавать), а какой бэкенд - не столь важно.

Как известно, за expire сессий отвечают 2 параметра в конфиге: $c->config->{session}->{expires} и $c->config->{session}->{cookie_expires}, которые отвечают за экспайр сессии и куки соответственно.

cookie_expires использует только Catalyst::Plugin::Session::State::Cookie, причем на стороне сервера оно нигде не хранится, и используется только для выставления expire в HTTP-заголовке. Причем если cookie_expires == 0, то кука будет сессионная.

expires использует Catalyst::Plugin::Session. Когда происходит запрос с проэкспайренной сессией, вызываются методы delete_session_id и delete_session_data. Первый наследуется Session::State (т.о. может удалить куку, даже если она еще не проэкспайрилась), второй - наследуется Session::Store. Его предназначение - удалить данную сессию на сервере.

Результат

Таким образом со стороны пользователя получается всё прозрачно. Выставляем expires == cookie_expires и всё. Т.к. если cookie_expires будет больше - сессия на сервере истечет раньше, будет вызван delete_session_id, и кука всё равно удалится. Наоборот - кука удалится, данные сессии на сервере останутся, но пользователю это неважно - для него этой сессии больше нет.

Немного сложнее с сессионными куками (cookie_expires == 0). Здесь надо выставить expires во что-нибудь вменяемое, например - сутки. Крайне маловероятно, что пользователь не закроет сайт в браузере в течение суток, и при этом ни разу не запросит ни одной страницы.

Проблемы

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

Каталист предлагает "свалить" эту проблему на Session::Store::бэкенды.

Catalyst::Plugin::Session::Store
delete_expired_sessions
This method is not called by any code at present, but may be called in the future, as part of a Catalyst-specific maintenance script.
If you are wrapping around a backend which manages its own auto expiry you can just give this method an empty body.

Но реальность обстоит иначе:

Catalyst::Plugin::Session::Store::DBI
The expires column in your table will be set with the expiration value. Note that no automatic cleanup is done on your session data, but you can use the delete_expired_sessions method to perform clean up. You can make use of the Catalyst::Plugin::Scheduler plugin to schedule automated session cleanup.
Т.о. забота об очистке сессионного хранилища кладется на нас.

Catalyst::Plugin::Session::Store::File
Здесь всё вообще "замечательно":

sub delete_expired_sessions { }

Метод тупо не реализован :) Более того:

    $c->_session_file_storage(
        Cache::FileCache->new(
            {
                cache_root  => $cfg->{storage},
                (
                    map { $_ => $cfg->{$_} }
                      grep { exists $cfg->{$_} }
                      qw/namespace cache_depth directory_umask/
                ),
            }
        )
    );

Как мы видим, модуль вообще не заботится об expire, и даже параметра такого в Cache::File не передает. Т.о. даже невозможно написать maintenance-скрипт, который бы чистил периодически хранилище.

About this Archive

This page is an archive of recent entries in the Catalyst category.

Find recent content on the main index or look in the archives to find all content.

Pages

Powered by Movable Type 4.2-en