timvdalen's avatar

Accessing the Scheduling from Lumen ServiceProvider

I'm trying to schedule commands from a Lumen ServiceProvider.

In Laravel, the community points out that you need to wait for everything to be booted before you can access the Schedule (https://stackoverflow.com/a/36630136/451847, https://laracasts.com/discuss/channels/laravel/binding-schedule-in-laravel-package).

However, a Lumen application does not have a booted callback.

The following service provider does not register the command:

<?php
namespace CodeOrange\Statuspage;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Support\ServiceProvider;

class ExampleProvider extends ServiceProvider {
    public function boot(Schedule $s) {
        $s->call(function () {
            echo "test\n";
        })->everyMinute();

        $s2 = $this->app->make(Schedule::class);
        $s2->call(function () {
            echo "test\n";
        })->everyMinute();
    }
}

Is there any way to access the schedule from a ServiceProvider or should I instruct dependants of my package to schedule the command in their Kernel?

0 likes
2 replies
timvdalen's avatar

As a followup, the reason for this seems to be that the Schedule instance isn't added to the service container until the application's Console\Kernel is constructed (and defineConsoleSchedule() is called).

In the ExampleProvider provided above, the application just resolved a fresh instance of Schedule both when injecting it into boot() and when it is explicitly requested.

The question now becomes: is there any way to register a callback for when the Kernel has been created?

timvdalen's avatar

Okay, I got a bit further but I think I've run into a limit in the framework.

Since Kernel is registered as a singleton in the bootstrapping process, I figured injecting a Kernel instance in ExampleProvider would make sure I could get the correct instance of Schedule. Turns out this idea was partly correct: I can access the correctly registered instance of Schedule after I inject Kernel into ExampleProvider.

However, this only works within application context (if the application was started from public/index.php. In an artisan context, two Kernel instances are created.

I'm not sure how or why, but https://github.com/laravel/lumen/blob/912befc/artisan#L31-L33 makes a new instance of Kernel (despite being declared as a singleton and another instance already existing). This is the Kernel instance that's ultimately used when executing the schedule, so any changes to the schedule of the previously created Kernel are lost.

At this point, I'm not sure if there is another approach - I'm also not entirely sure if this is a bug or expected behaviour. For now, I'll require my users to explicitly call my provider from their schedule, which will result in the schedule being set twice (and on the Kernel that will be used for execution).

Please or to participate in this conversation.