nuclearcoconut's avatar

Singleton is running again and again

I would like to make a request to the 3rd party app API when my Laravel app is run for the first time. For this purpose I use singleton:

AppServiceProvider.php

public function boot() { $this->app->singleton(InitializeRoles::class, function() { return new InitializeRoles(); }); }

And my InitializeRoles.php:

class InitializeRoles {

public function __construct()
{
    // some request to the API server
}

}

But I noticed that everytime I browse through my app pages, the request is sent again and again. Should the singleton run once and send the request only once? So why is it sending it more than 1 time?

0 likes
10 replies
MichalOravec's avatar

@nuclearcoconut Put it to the register method instead of boot

public function register() 
{ 
    $this->app->singleton(InitializeRoles::class, function () { 
        return new InitializeRoles(); 
    }); 
}

Singleton is called just once for every request.It's a normal behaviour.

If you don't want to execute that code you can use cache for it with singleton.

use Illuminate\Support\Facades\Cache;

public function register() 
{ 
    $this->app->singleton(InitializeRoles::class, function () { 
        return Cache::remember('roles', now()->addDay(), function () {
            return new InitializeRoles(); 
        });
    }); 
}
nuclearcoconut's avatar

Thank you for your reply, but, unfortunately, the result is the same.

Snapey's avatar

@nuclearcoconut You are not understanding how PHP works.

The entire application is destroyed between requests. Your singleton therefore only lasts the duration of the request, and not from one API call to the next.

I hope that is clear?

2 likes
huunv's avatar

@Snapey If the singleton only lasts during of the request execution, then what make it different from Scoped one? I'm not very clear on this.

Snapey's avatar

@huunv a singleton will only be instantiated once (per request). Each time you ask the container for an instance of the class, you will get the same instance. Whereas other methods of instantiating classes out of the container will give you a fresh copy each time.

But above all else, unless you are running Octane, php tears everything down at the end of the request cycle

nuclearcoconut's avatar

Yes, sir, it is definitely clear now. But where should I store such type of code that involves only one-time request to an external API?

Snapey's avatar

when my Laravel app is run for the first time

define 'first time'

nuclearcoconut's avatar

I suppose, when the Service Containers are deployed. Something that could be called from AppServiceProvider's boot method, but only once.

Snapey's avatar
Snapey
Best Answer
Level 122

But they are deployed on every request. Your application has no 'state' between requests.

Just say, for sake of argument, I was accessing a web service, for which I had to get an access token. When I have that token, it is valid for 8 hours and then has to be refreshed. Now, I would not want to get a new token on every request as that would a) slow my app, and b) not be accepted by the API provider.

So, what would I do ? I would store the current token in some form of non-volatile storage such as the database, a redis store or even a file in the file system.

Then when each request comes in, I can check that I have a token that is not too old, and then use that. If the token has expired then I would get a new one and store it again.

You cannot do this with a singleton as it is lost as soon as the request completes.

1 like
nuclearcoconut's avatar

Thank you, sir, for the detailed explanation. That is exactly what I needed.

Please or to participate in this conversation.