Для хранения сессий я использую Spring Session и Redis. То есть сессия хранится не в памяти, а в БД.
Есть пользователь. Пользователь может начать проходить тест. То есть с сервера приходит вопрос, пользователь даёт ответ, и так пока вопросы не кончатся. Когда они кончатся, надо записать в БД результат теста.
Проблема вот в чём. Я собираюсь хранить ответы пользователя (у ещё не пройденного до конца теста) в сессии, а сессия сохраняется в Redis. И пользователь может уйти со страницы, закрывать вкладку и т.д., а потом вернётся назад и, если сессия у него всё ещё открыта, то он будет проходить тест с середины.
А я хочу, чтобы в таких случаях он проходил тест с самого начала! Как я мог сделать сброс теста? На ум приходит пингование. Буду постоянно пинговать, каждые 5 секунд буду устанавливать в сессию время последнего пинга, а при запросах пользователя на получении нового вопроса будет делать проверка - а когда был последний пинг? Если давно, то сбрасывать тест. Но это решение кажется костыльным.
Eugenue Cesarevich вначале теста генерируете ключ, кладете в redis с нужным TTL и передаете его через ajax, сохраняете в переменной javascript, с каждым ответом передаете этот ключ до окончания теста, на стороне сервера увеличиваете счетчик этого ключа по количеству ответов. Если нет ключа - всегда первый вопрос, если счетчик увеличивается больше чем на единицу - сбрасываете тест и удаляете ключ (это читер).
Можно на каждый вопрос генерировать ключ и все ключи разом передавать с ключем теста, тогда для каждого ответа отправляем два ключа (ключ теста и ключ вопроса). На стороне сервера удаляем ключ вопроса из SET. Ответ не принимаем, если нет ключа вопроса в соответствии с ключом теста.
Другими словами:
1) Генерируем ключ теста и генерируем к каждому вопросу ключ вопроса, записываем в SET (SADD "my-test-key-XXXX" "my-query-key-XXX" ... "my-query-key-ZZZ")
1.1) EXPIRE "my-test-key-XXXX" 3600
2) Передаем массив ключей
3) Проверяем ключ теста и ключ вопроса, удаляем ключ вопроса из сета
Если вопросы последовательные, то можно хранить в массиве, проверяя еще и индекс ключа.
Алексей Черемисин, черт, это классный вариант. Хранить ключ-переменную на стороне клиента неплохой вариант. Попробую. Только напрямую к редису разве надо обращаться? Я просто в httpsession буду данные класть, он автоматически в редис сохраняется.
Алексей Черемисин, не я понял. Может по своему немного... Ну вот как я решил:
1. Получаем ключ на UI. Ключ сохраняем в сессию (иначе как определять данные-то будем?).
2. Если пользователь перезагружает страницу или уходит, ключ на UI теряется.
3. Пользователь пытается пройти тест, ему говорят: ключа нет, иди отсюда.
Алексей Черемисин, ну да, ключ будет валяться. Но этот же самый ключ должен будет храниться на UI. А когда UI перезагружен, то ключ исчезнет. И тогда пользователь сделает запрос и, так как ключа у него не будет, данные будут стёрты и будет загружен новый тест.
Для правильного вопроса надо знать половину ответа
Можно передать с сервера сразу все вопросы, на клиенте показывать их по очереди или в произвольной последовательности, а в конце отправлять сразу все ответы.