Symfony 2.1 Session Handler MongoDB MongoTimestamp Bug

mongodbВ этом посте я расскажу, почему нельзя использовать MongoDbSessionHandler в Symfony 2.1 и о том, к чему это привело. А привело это к довольно долгому поиску и анализу бага, который изрядно подпортил нам нервы и заставит нецензурно ругаться в адрес одного француза.

 

Проблема

Сидел я себе спокойно в своей веточке в git-е, кодил помаленьку, никому не мешал. И вот наконец фича готова, протестирована, и надо проверить её в продакшен окружении. Выкатываем код на несколько минут, сначала всё идёт нормально, а потом бац, сервер отваливается (ошибка по бд MongoDB). Откатываем код – веб-сервер лежит, чистим сессии – он восстанавливается. Wtf?

Анализ

Мы понимали, что косяк как-то связан с сессиями, но конкретно проблему воспроизвести не могли. На девелоперских машинах всё отрабатывало нормально, на stage – тоже, и баг никак не ловился. Но разобраться с ним надо было. Стоит заметить, что в данный момент мы используем параллельно два механизма доступа к сессиям (Zend Framework 1.x Session и Symfony 2 Session). Это конечно не по фен-шую и создаёт ряд неудобств, но явление, как-таковое – временное. При этом Sf2 сессии были только в моей ветке, а Zf – в апстриме. Следовательно надо копаться именно в реализациях сессий в симфони. И я начал копаться. Ошибка на продакшене была такая:

Это значит, что произошло несовпадение типа в поле документа и типа в поле индекса. После этого репликация становится невозможной и база падает. А за ней падает и PHP, и веб-сервер.

mongodb-tatoo

Я начал смотреть MongoDbSessionHandler и наш админ обратил моё внимание вот на этот кусок кода.

Поле time_field использует тип MongoTimestamp. Смотрим доку по нему (http://php.net/manual/en/class.mongotimestamp.php). А там написано следующее:

Данный класс используется только для шардинга, в других случаях надо использовать вместо него MongoDate. Что кстати и сделано в Symfony 2.2.

В итоге, когда монго-реплика пытается проиндексировать коллекцию с документом, в котором есть поле MongoTimestamp – она падает. Потом так же падает вторая реплика в реплика-сете, остаётся одинокий мастер – который падает в слейв. Отдельное спасибо нашему админу, что помог разобраться в проблеме.

Решение

Так что совет будет такой: либо переходите на версию Symfony 2.2, либо в случае с 2.1 делайте кастомный SessionHandler в котором руками исправляйте соответствующие строки.

 

Leave a Comment