Заметное увеличение времени при проверке разрешений после обновления с laravel 5.7 до laravel 5.8 с использованием silber / bouncer-rc5 - PullRequest
2 голосов
/ 24 апреля 2019

Я использую bouncer для своих потребностей ACL, и с тех пор, как я обновил свой проект с laravel 5.7 до 5.8, я заметил значительное увеличение времени, которое требуется для обработки моих запросов.

Я имею дело с двумя моделями (назовем их Parent и Child), а также с разрешениями, которые аутентифицированный пользователь имеет над ними.

// Takes about 110ms. Eager loads various nested relationships and counters with specific constraints
$parents = Parent::myScope(...)->get();

// Bottleneck. Takes 5 minutes (!). Used to take about 40 seconds on laravel 5.7
$parents->each(function ($parent) {
    $parent->permissions = [
        'edit' => auth()->user()->can('edit', $parent),
        'delete' => auth()->user()->can('delete', $parent),
        'restore' => auth()->user()->can('restore', $parent)
    ];
    $parent->children()->each(function ($child) {
        $child->permissions = [
            'edit' => auth()->user()->can('edit', $child),
            'delete' => auth()->user()->can('delete', $child),
            'restore' => auth()->user()->can('restore', $child)
        ];
    }
}

Я добавляю такие разрешения, потому что переменная $parents будет отправлена ​​как json во внешний интерфейс. Я почти уверен, что эта реализация неверна и должна иметь лучшую альтернативу, но реальная проблема - это необъяснимое пятикратное увеличение времени загрузки.

Время было получено с использованием Debugbar мер.

Используя команду monitor в redis-cli (я использую Redis для кэширования разрешений), я заметил, что запросы GET приходят медленнее, чем раньше. Фактически, даже после того, как я прекращаю загрузку страницы ( ESC ), запросы GET к Redis не прекращаются немедленно. Я не уверен, нормальное ли это поведение или нет.

Я пытался проверить проблемы в репозитории, но ничего не нашел.

Ответы [ 2 ]

1 голос
/ 25 апреля 2019

Вы звоните auth()->user() сотни раз.Можете ли вы попробовать вызвать его только один раз?

$user = auth()->user();

$parents->each(function ($parent) use ($user) {
    $parent->permissions = [
        'edit' => $user->can('edit', $parent),
        'delete' => $user->can('delete', $parent),
        'restore' => $user->can('restore', $parent)
    ];

    $parent->children()->each(function ($child) {
        $child->permissions = [
            'edit' => $user->can('edit', $child),
            'delete' => $user->can('delete', $child),
            'restore' => $user->can('restore', $child)
        ];
    }
}

Кроме того, поскольку вы загружаете children, вам не следует извлекать их все снова в каждой итерации цикла:

$parent->children()->each(function ($child) {
//               ^^ remove these parentheses
    $child->permissions = [
        'edit' => $user->can('edit', $child),
        'delete' => $user->can('delete', $child),
        'restore' => $user->can('restore', $child)
    ];
}
0 голосов
/ 26 апреля 2019

После некоторого тестирования решение было найдено.Оказывается, с кодом проблем не было вообще.

Что-то не так с сервером.Мы не знаем точно, что, но попытка запустить проект на только что установленных машинах избавила нас от этих ужасных времен обработки.(Сейчас время составляет 15 секунд при первом запросе)

Проблема сервера усугубилась случайно после перехода с laravel 5.7 на 5.8, что привело меня к этой погоне за диким гусем.

ADDENDUM

Виновником был Xdebug.Мы использовали его для анализа покрытия кода, но производительность была настолько плохой, что мы в итоге переключились на phpdbg.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...