Механизм
Как известно, механизм сессий построен по принципу 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-скрипт, который бы чистил периодически хранилище.
Спасибо за инфу. Полезно.
Спасибо за ценную информацию.