Блокировка сеанса phpredis не может получить блокировку, выдает уведомление php о фатальной ошибке

При использовании php redis в качестве обработчика сеанса с блокировкой сеанса, если возникает ошибка, из-за которой блокировка не может произойти php выдается уведомление, и сценарий продолжается. Есть ли способ настроить его на фатальную ошибку, и скрипт вообще НЕ обрабатывается?


person Chris Muench    schedule 03.02.2020    source источник
comment
вы можете использовать структуры управления/условия, чтобы проверить блокировку сеанса, если это не удается, throw new Exception()   -  person treyBake    schedule 03.02.2020
comment
Я не вижу способа сделать это, потому что блокировка происходит вне моего приложения через модуль php redis.   -  person Chris Muench    schedule 03.02.2020
comment
Помимо редактирования кода пакета, в котором происходит обработка ошибок, это может вам помочь: in-php-code" title="есть ли способ заметить электронное уведомление в php-коде"> stackoverflow.com/questions/51364016/   -  person SJacks    schedule 21.09.2020
comment
Это именно то, что я искал. Спасибо!   -  person Chris Muench    schedule 21.09.2020


Ответы (2)


Убедитесь, что вы следуете этому утверждению документации:

В настоящее время функция блокировки поддерживается только для установки Redis с одним главным экземпляром.

Если у вас все еще есть какие-то проблемы, быстрое решение для всего приложения может быть установлено вашим собственным обработчиком ошибок с помощью set_error_handler, который решает эту конкретную проблему. Пример обработчика ниже, который реагирует только на использование не объявленной переменной. Измените шаблон регулярного выражения, чтобы он соответствовал вашему сообщению об ошибке Redis.

<?php

error_reporting(E_ALL);

$redisNoticeFunction = function($errno, $errstr, $errfile, $errline, array $errcontext) {

    // is the error E_NOTICE?
    if ($errno === \E_NOTICE) {
            
        // if error was suppressed with the @-operator
        if (0 === \error_reporting()) {
            // do nothing, continue execution of script
            return;
        }
        
        // check if notice is about Redis
        $pattern = '/.*Undefined variable.*/'; // <== change pattern so it matches notice about Redis
        $subject = $errstr;
        $status = \preg_match($pattern, $subject);
        
        // if there was a problem with regex
        if (false === $status) {
            $msg = 'Could not perform preg_math with pattern: ' . $pattern . ' and subject: ' . $subject . \PHP_EOL;
            // exit by throwing an exception
            throw new \InvalidArgumentException($msg);
        }

        // if notice was about about Redis
        if ($status) {
            $error_msg = 'Redis locking problem with notice msg: ' . $errstr;
            $error_msg .= ' at ' . $errfile . ':' . $errline . \PHP_EOL;
            
            // signal fatal error
            $error_type = \E_USER_ERROR;
            \trigger_error ($error_msg, $error_type);
            
            // or throw exception (comment above line with \trigger_error())
            throw new \RuntimeException($error_msg);
        }

        // the notice was not related to the Redis
        // echo its message and continue script
        echo $errstr . \PHP_EOL;
        return;
    }

    // the error was not the E_NOTICE
    // do other error handling if needed

    // or just end the script
    die;

};

set_error_handler($redisNoticeFunction);    

echo @ $notDeclared; // does not end script

echo $notDeclared; // end script or throws an exception

последняя строка

echo $notDeclared; // end script or throws an exception

заканчивает скрипт информацией:

Неустранимая ошибка: проблема блокировки Redis с уведомлением msg: Неопределенная переменная: notDeclared в /tmp/index.php:59

set_error_handler следует использовать в начале вашего php скрипт (идеально внутри общего файла, который требуется везде как bootstrap.php)

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

Если вы хотите вернуться к исходному обработчику ошибок (по умолчанию из PHP или к тому, который был установлен перед вашим собственным), используйте restore_error_handler

person Jimmix    schedule 21.09.2020

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

function redisNoticeFunction($errno, $errstr, $errfile, $errline, array $errcontext) 
{
    // is the error E_NOTICE?
    if ($errno === E_NOTICE) 
    {
        // if error was suppressed with the @-operator
        if (0 === error_reporting()) 
        {
            // do nothing, continue execution of script
            return;
        }
    
        // if notice was about about Redis locking
        if ($errstr == 'session_start(): Acquire of session lock was not successful') 
        {
            $error_msg = 'Redis locking problem with notice msg: ' . $errstr;
            $error_msg .= ' at ' . $errfile . ':' . $errline . \PHP_EOL;

            // signal fatal error
            $error_type = E_USER_ERROR;
            trigger_error ($error_msg, $error_type);
        }
        return;
    }
}

$current_error_reporting = error_reporting();
error_reporting(E_ALL);
set_error_handler('redisNoticeFunction');


session_start();
//Use regular error handling if session_start() does not end in a lock
restore_error_handler();
error_reporting($current_error_reporting);
person Chris Muench    schedule 23.09.2020