На данный момент мое решение состоит в том, чтобы проверить, есть ли уже блокировка файла сеанса, используя exec сценарии оболочки. Я не рекомендую использовать его тем, кто не полностью понимает его.
В основном он пытается получить блокировку файла сеанса для указанного значения времени ожидания, используя flock
.Если это не удается сделать, он существует с тайм-аутом 408 запроса.(или 429 Слишком много запросов, если доступно)
Чтобы это работало, вам необходимо ...
- знать свой идентификатор сеанса на тот момент времени
- есть файловые сессии
Обратите внимание, что это не атомарное .Все еще может случиться так, что несколько запросов в конечном итоге ожидают в session_start.Но это должно быть редкое событие.Большинство вызовов должны быть отменены правильно, что было моей повесткой дня.
class Session {
static public function openWhenClosed() {
if (session_status() == PHP_SESSION_NONE) {
$sessionId = session_id();
if ($sessionId == null)
$sessionId = $_COOKIE[session_name()];
if ($sessionId != null) {
$sessFile = session_save_path()."/sess_".$sessionId;
if (file_exists($sessFile)) {
$timeout = 30; //How long to try to get hold of the session
$fd = 9; //File descriptor to use to try locking the session file.
/*
* This 'trick' is not atomic!!
* After exec returned and session_start() is called there is a time window
* where it can happen that other waiting calls get a successful lock and also
* proceed and get then blocked by session_start(). The longer the sleep value
* the less likely this is to happen. But also the longer the extra delay
* for the call
*/
$sleep = "0.01"; //10ms
//Check if session file is already locked by trying to get a lock on it.
//If it is, try again for $timeout seconds every $sleep seconds
exec("
exec $fd>>$sessFile;
while [ \$SECONDS -lt $timeout ]; do
flock -n $fd;
if [ \$? -eq 0 ]; then exit 0; fi;
sleep $sleep;
done;
exit 1;
", $null, $timedOut);
if ($timedOut) {
http_response_code(408); //408: Request Timeout. Or even better 429 if your apache supports it
die("Request canceled because another request is still running");
}
}
}
session_start();
}
}
}
Дополнительные мысли:
- Заманчиво использовать
flock -w <timeout>
но такгораздо больше ожидающих в очереди вызовов смогут использовать время между exec
и start_session
для получения блокировки и в конечном итоге блокировать в session_start
- Если вы используете браузер для тестирования этого, имейте в виду, чтобольшинство браузеров делают очереди команд и повторно используют ограниченное количество соединений.Поэтому они не начинают отправлять ваш запрос раньше, чем другие завершат.Это может привести к, казалось бы, странным результатам, если вы не знаете об этом.Вы можете более надежно тестировать, используя несколько параллельных команд
wget
. - Я не рекомендую активировать это для обычного запроса браузера.Как упомянуто в 2), в большинстве случаев это уже обрабатывается браузером.Я использую его только для защиты моего API от реализаций румян, которые не ждут ответа перед отправкой следующего запроса.
- В моих тестах для моей общей нагрузки снижение производительности было незначительным.Но я бы посоветовал проверить себя в вашей среде, используя
microtime()
звонки