• Час читання ~2 хв
  • 19.06.2023

Деякий час тому я почав замислюватися про тривалий час завантаження програми, заснованої на Laravel. Я почав налагодження і зрозумів, що ця проблема пов'язана з відсутністю відкладених провайдерів. Це було дивно, тому що ми використовували багато відкладених провайдерів. Після додаткового налагодження ми виявили, що AggregateProviders не поважає відкладених постачальників.

Проблема Наш

додаток мав понад 60 постачальників агрегатних послуг, подібних до наступного:

use Illuminate\Support\AggregateServiceProvider;

final class SampleProvider extends AggregateServiceProvider
{
    protected $providers = [
        EventsProvider::class,
        ImplementationsProvider::class,
        RoutingProvider::class,
    ];
}

У цьому випадку, згідно з документацією:Якщо

ваш постачальник реєструє лише прив'язки в контейнері послуг, ви можете відкласти його реєстрацію до тих пір, ImplementationsProvider implements \Illuminate\Contracts\Support\DeferrableProvider поки одне із зареєстрованих прив'язок насправді не знадобиться. Відстрочка завантаження такого провайдера покращить продуктивність вашого додатка, оскільки він завантажується з файлової системи не за кожним запитом.

https://laravel.com/docs/10.x/providers#deferred-providersЯкщо ми подивимося на регістр методу\Illuminate\Support\AggregateServiceProvider, то побачимо наступну реалізацію:Це означає,

public function register()
{
    $this->instances = [];

    foreach ($this->providers as $provider) {
        $this->instances[] = $this->app->register($provider);
    }
}

що кожен постачальник, доданий до AggregateServiceProvider, буде негайно зареєстрований за кожним запитом, оскільки для реєстрації відкладеного постачальника в контейнері слід використовувати метод registerDeferredProvider($provider, $service = null);.

Не використовуйте AggregateServiceProvider Отже, висновок простий, не використовуйте AggregateServiceProvider

. Я рекомендую використовувати щось подібне:

final class SampleProvider
{
    /**
     * @return string[]
     */
    public static function providers(): array
    {
        return [
            EventsProvider::class,
            ImplementationsProvider::class,
            RoutingProvider::class,
        ];
    }
}

Тоді в конфігурації ми можемо завантажити постачальників так:

'providers' => array_merge(
    // ...
    \App\Modules\Module\SampleProvider::providers(),
    // ...
);

Тест для перевірки методу

надання Легко помилитися під час рефакторингу цих постачальників, тепер ми повинні правильно налаштувати метод надання у всіх відкладених постачальників, оскільки вони будуть завантажені лише тоді, коли потрібна певна залежність, і контейнер повинен знайти відповідного постачальника з визначенням цієї залежності. Тому було б добре написати власне правило PHPStan або просто трохи хитрий тест в PHPUnit.

Результати після часткового рефакторингу Виконуючи частковий рефакторинг

цієї проблеми (2/3 AggregateServiceProviders), ми змогли скоротити час завантаження програми більш ніж на 20%. Це, ймовірно, всього кілька мілісекунд на запит (я оцінюю прибуток 5 мс), звичайно, не надто багато, але це має значення для кожного запиту. Крім того, в майбутньому, коли додаток буде рости, це буде більшою проблемою, тому краще розібратися в цій проблемі і не впливати на продуктивність таким дурним способом.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297