Подтвердить что ты не робот

Laravel 5 проигрывает сеансы и значения конфигурации .env в приложениях с интенсивным использованием AJAX

Я использую Laravel 5 (чтобы быть конкретным, версия laravel/framework "v5.0.27" ), с драйвером session = 'file'.

Я разрабатываю 64-разрядную машину Windows 7.

Я заметил, что иногда (раз в неделю или около того) я неожиданно и случайно выхожу из системы. Иногда это происходит даже сразу после входа в систему. Я добавил сообщения журнала в мой логический код, но код журнала не был запущен. Laravel вел себя так, как будто он полностью потерял файл сеанса.

Еще одна серьезная проблема заключалась в том, что иногда после отладки сессий (с использованием xdebug и Netbeans) Laravel начал проигрывать и другие файлы - настройки .env, некоторые файлы JS debugbar и т.д. В журнале ошибок были такие сообщения, как:

[2015-07-08 13:05:31] local.ERROR: exception 'ErrorException' with message 'mcrypt_encrypt(): Key of size 7 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported' in D:\myproject\vendor\laravel\framework\src\Illuminate\Encryption\Encrypter.php:81
[2015-07-08 13:05:31] local.ERROR: exception 'PDOException' with message 'SQLSTATE[HY000] [1044] Access denied for user ''@'localhost' to database 'forge'' in D:\myproject\vendor\laravel\framework\src\Illuminate\Database\Connectors\Connector.php:47

Это ясно говорит о том, что файл .env не был прочитан Laravel, поэтому он использует настройки по умолчанию:

'database'  => env('DB_DATABASE', 'forge'),
'key' => env('APP_KEY', 'somekey'),

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

Чтобы стресс-тест системы и достоверность воспроизведения вопросов, я использовал быстрый взлом в моем контроллере Angular:

setInterval(function(){
    $scope.getGridPagedDataAsync();
}, 500);

Это просто базовый запрос данных от Angular к Laravel.

И это все - теперь я могу воспроизвести проигрывание сессии и потерять .env через 3 минуты или меньше.

Я разработал AJAX-интенсивные веб-приложения ранее на том же ПК с тем же Apache + PHP, но без Laravel, без .env, и я раньше не замечал таких проблем.

Во время отладки через код я узнал, что Laravel не использует встроенные сессии PHP вообще, но реализовал свой собственный сеанс на основе файлов. Очевидно, что он не обеспечивает такую ​​же надежность, как и PHP-сессии по умолчанию, и я не уверен, почему.

Конечно, в реальных сценариях мое приложение не будет таким интенсивным AJAX, но в моих опытах в некоторых случаях достаточно всего двух одновременных запросов AJAX, чтобы потерять сеанс.

Я видел некоторые связанные отчеты об ошибках в Laravel для различных вопросов сессии. Однако я еще ничего не видел о dot-env, но, похоже, он страдает от той же проблемы.

Я предполагаю, что Laravel не использует блокировки файлов и ожидания, поэтому, если файл по какой-либо причине не может быть прочитан (возможно, заблокирован каким-то параллельным процессом или Apache), то Laravel просто отказывается и возвращает все, что может.

Есть ли хорошее решение для этого? Может быть, это специфично для Windows, и проблемы исчезнут на машине Linux?

Любопытно, почему разработчики Laravel (или Symfony) еще не исправили свой файл сеансовых файлов. Я знаю, что блокировка/ожидание замедлит его, но было бы здорово хотя бы иметь возможность включить "надежные сеансы".

Тем временем я попытаюсь выполнить код Laravel и посмотреть, смогу ли я придумать какое-нибудь "быстрое и амбициозное" исправление, но было бы гораздо лучше иметь какое-то надежное и "лучшее" решение.

Обновление о .env

Проблема не связана с блокировкой файлов. Я нашел отчет об ошибке Laravel для проблемы .env, который привел меня к связанному отчету для проекта Dotenv, который, в свою очередь, говорит, что это основная проблема PHP. Меня беспокоит то, что дотенвские разработчики говорят, что Дотенв никогда не предназначался для производства, но Ларавель, похоже, полагается на Дотенва.

В https://github.com/laravel/framework/pull/8187 похоже решение, которое должно работать в одном направлении, но некоторые комментаторы говорят, что в их случае проблема была противоположной. Кто-то, называемый crynobone, дал умный фрагмент кода, чтобы попробовать:

$value = array_get($_ENV, $key, getenv($key));

Появилось другое предложение использовать "makeMutable()" как для Dotenv, так и для Laravel Githubs, но комментаторы сообщают, что это может нарушить тесты.

Итак, я попробовал crynobone, но для меня это не сработало. Во время отладки я узнал, что в случае, когда что-то ломается для одновременных запросов, ключ $не может быть найден ни в getenv(), ни в $_ENV, ни даже в $_SERVER. Единственное, что сработало (quick & dirty experminet), заключалось в том, чтобы добавить:

static:: $cached [$ name] = $value;

в класс Dotenv, а затем в helpers.php env(), я вижу, что:

Dotenv::$cached[$key]

всегда хорош, даже когда $_ENV и getenv оба ничего не дают.

Хотя Dotenv не предназначался для производства, я не хочу менять рабочий процесс развертывания и конфигурации.

Далее мне придется исследовать проблемы сессии...


Добавление

Связанные отчеты об ошибках Laravel (некоторые даже из версии 4. и, похоже, не исправлены): https://github.com/laravel/framework/issues/4576

https://github.com/laravel/framework/issues/5416

https://github.com/laravel/framework/issues/8172

и старую статью, которая проливает свет на то, что происходит (по крайней мере, с проблемами сеанса): http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/

4b9b3361

Ответ 1

Мое личное мнение, что использование .env для настройки Laravel - плохое решение. Наличие файлов .php, содержащих ключ: значение стиля конфигурации было намного лучше.

Однако проблема, с которой вы сталкиваетесь, - это не ошибка PHP, а Apache - это, скорее всего, проблема с Windows.

Несколько вещей: Apache содержит модуль, который позволяет интегрировать PHP-бинар в процесс или поток Apache, называемый mod_php - проблема заключается в том, что PHP не только медленный, но и другой бинарный интегрированный в существующий один супер сложно, и вещи могут быть упущены. В этом случае PHP также должен быть построен с обеспечением безопасности потоков. Если это не так, тогда могут возникнуть (и будут) странные ошибки.

Чтобы обойти проблему сложной интеграции одной программы в другую, мы можем полностью ее избежать, и мы можем .php обслуживать протокол FastCGI. Это означает, что веб-сервер (Apache или Nginx) будет принимать HTTP-запрос и передавать его на другой "веб-сервер". В нашем случае это будет PHP FastCGI Process Manager или PHP-FPM.

PHP-FPM является предпочтительным способом обслуживания .php страниц - не только потому, что он быстрее (гораздо быстрее, чем интеграция через mod_php), но вы можете легко масштабировать свой интерфейс HTTP и иметь несколько машин, обслуживающих .php страниц, что позволяет легко горизонтально масштабировать ваш интерфейс HTTP.

Однако PHP-FPM - это что-то, называемое процессом супервизора, и оно зависит от управления процессом. Насколько мне известно, Windows не поддерживает управление процессами так, как это делает * nix, поэтому PHP-FPM недоступен для Windows (в случае, если я ошибаюсь, пожалуйста, исправьте меня).

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

  • Веб-сервер принимает HTTP-запросы (Apache или Nginx)
  • Веб-сервер проверяет запрос, анализирует необработанный HTTP-запрос, определяет, является ли запрос слишком большим, и если в этом случае все будет хорошо, он проксирует запрос на PHP-FPM.
  • PHP-FPM обрабатывает запрос (в вашем случае он загружает Laravel) и возвращает HTML, который веб-сервер показывает пользователю.

Теперь этот процесс в то время как отличный, имеет несколько проблем, и одна огромная проблема заключается в том, как PHP работает с сеансами. По умолчанию PHP-сессия - это файл, хранящийся где-то на сервере. Это означает, что если у вас есть 2 физических аппарата, обслуживающих ваш PHP-FPM, у вас будут проблемы с сеансами. Здесь Laravel делает что-то отличное - он позволяет вам использовать зашифрованные сеансы на основе файлов cookie. Он имеет ограничения (вы не можете хранить ресурсы на этих сеансах, и у вас есть ограничение по размеру), но правильно построенное приложение не будет хранить слишком много информации в сеансе в первую очередь. Есть, конечно, несколько способов общения с сеансами, но, на мой взгляд, зашифрованный куки файл супер, супер тривиальный для использования и мощный. Когда такой куки файл используется, клиент, который несет информацию о сеансе и любую машину, которая содержит ключ дешифрования, может прочитать этот сеанс, что означает, что вы можете легко масштабировать свою настройку на нескольких серверах - все, что им нужно сделать, это иметь доступ к тем же ключ дешифрования (это APP_KEY в .env). В основном вам необходимо скопировать ту же установку Laravel на машины, которые вы хотите обслуживать своим проектом.

То, как я буду заниматься проблемой, которую вы сейчас разрабатываете, выглядит следующим образом:

  • Используйте виртуальную машину (скажем, Oracle Virtualbox)
  • Установить Ubuntu 14.04
  • Сопоставьте сетевой диск с хост-машиной Windows (используя Samba)
  • Используйте ваш предпочтительный способ редактирования файлов PHP, но они будут сохранены на подключенном диске.
  • Загрузите nginx или Apache вместе с PHP-FPM на виртуальной машине, чтобы обслуживать ваш проект.

Теперь то, что вы получаете через этот процесс, таково: вы не загрязняете свою машину Windows программой, которая слушает на портах 80/443, когда вы закончите работу, вы можете просто закрыть виртуальную машину без потери работы, вы также может легко имитировать, как ваш сайт будет вести себя на реальной производственной машине, и у вас не будет сюрпризов, таких как "он работает на моей машине для разработчиков, но он не работает на моей производственной машине", потому что у вас будет такое же программное обеспечение для обеим целям.

Это мои мнения, они не все холодные факты, и то, что я написал здесь, должно быть принято с солью. Если вы думаете, что то, что я написал, может вам помочь, тогда, пожалуйста, постарайтесь подойти к проблеме таким образом. Если нет, ну, никаких особых чувств, и я желаю вам удачи в ваших проектах.

Ответ 2

После двух дней интенсивной отладки у меня есть некоторые обходные пути, которые могут быть полезны для других:

Вот мой патч для Dotenv 1.1.0 и Laravel 5.0.27 для исправления проблем .env: https://gist.github.com/progmars/db5b8e2331e8723dd637

И вот мой патч для исправления, чтобы сделать проблемы сеанса гораздо менее частыми (или исправить их полностью, если вы не пишете на сеанс самостоятельно по каждому запросу): https://gist.github.com/progmars/960b848170ff4ecd580a

Я тестировал их с помощью Laravel 5.0.27 и Dotenv 1.1.0.

Также недавно воссозданные патчи для Laravel 5.1.1 и Dotenv 1.1.1: https://gist.github.com/progmars/e750f46c8c12e21a10ea https://gist.github.com/progmars/76598c982179bc335ebb

Убедитесь, что вы добавили

'metadata_update_threshold' => 1,

в ваш config/session.php, чтобы этот патч стал эффективным.

Все патчи должны применяться к папке vendor каждый раз, когда она воссоздается.

Также вы можете отделить сеанс патча, потому что вы обновляете session.php только один раз, но остальные части патча должны применяться к папке vendor каждый раз, когда они воссоздаются перед развертыванием.

Будьте предупреждены: "Это работает на моей машине". Я очень надеюсь, что разработчики Laravel и Dotenv придумают что-то лучшее, но пока я могу жить с этими исправлениями.