• Czas czytania ~2 min
  • 19.06.2023

Jakiś czas temu zacząłem się zastanawiać nad długim czasem bootstrap aplikacji opartej na Laravel. Rozpocząłem debugowanie i zorientowałem się, że ten problem był związany z brakiem odroczonych dostawców. To było dziwne, ponieważ korzystaliśmy z wielu odroczonych dostawców. Po dłuższym debugowaniu odkryliśmy, że AggregateProviders nie szanuje odroczonych dostawców.

Problem

Nasza aplikacja miała ponad 60 AggregateServiceProviders podobnych do następującego:W takim przypadku, zgodnie z dokumentacją

use Illuminate\Support\AggregateServiceProvider;

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

:

Jeśli Twój dostawca rejestruje tylko powiązania w kontenerze usług, możesz odroczyć jego rejestrację, ImplementationsProvider implements \Illuminate\Contracts\Support\DeferrableProvider dopóki jedno z zarejestrowanych powiązań nie będzie faktycznie potrzebne. Odroczenie ładowania takiego dostawcy poprawi wydajność aplikacji, ponieważ nie jest ona ładowana z systemu plików na każde żądanie.

https://laravel.com/docs/10.x/providers#deferred-providersJeśli spojrzymy na rejestrację \Illuminate\Support\AggregateServiceProvider metody, zobaczymy następującą implementację:Oznacza to, że każdy dostawca dodany do AggregateServiceProvider zostanie zarejestrowany natychmiast na każde żądanie, ponieważ aby zarejestrować odroczonego dostawcę w kontenerze,

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

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

należy użyć metody registerDeferredProvider($provider, $service = null);.

Nie używaj AggregateServiceProvider Więc wniosek jest prosty, nie używaj AggregateServiceProvider

. Polecam użycie czegoś takiego:Następnie w konfiguracji możemy załadować dostawców w ten sposób:

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

Test w celu zweryfikowania metody

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

zapewnia Łatwo jest popełnić błąd podczas refaktoryzacji tych dostawców, teraz musimy mieć odpowiednio skonfigurowaną metodę zapewnia we wszystkich odroczonych dostawcach, ponieważ zostaną one załadowane tylko wtedy, gdy potrzebna jest konkretna zależność,

a kontener musi znaleźć odpowiedniego dostawcę z definicją tej zależności. Dobrze byłoby więc napisać niestandardową regułę PHPStan lub po prostu trochę trudny test w PHPUnit.

Wyniki po częściowej refaktoryzacji

Wykonując częściową refaktoryzację tego problemu (2/3 AggregateServiceProviders) udało nam się skrócić czas bootstrap aplikacji o ponad 20%. To prawdopodobnie tylko kilka milisekund na żądanie (szacuję zysk 5 ms), oczywiście nie za dużo, ale robi różnicę na każdym żądaniu. Co więcej, w przyszłości, gdy aplikacja będzie się rozwijać, będzie to większy problem, więc lepiej zrozumieć ten problem i uniknąć wpływu na wydajność w tak głupi sposób.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297