Hi there,

I'm trying to create a scheduled task that runs once a month.

Not much is documented on it, so I'm trying to do some digging.

Here's what I got. So I extended/register the scheduler like bellow

    (new Extend\Console())
        ->schedule(\M\MyExtension\Console\InitCommand::class, function (Event $event) {
            $event->monthly();
        } )

And then the command.

class InitCommand extends Command{

    protected $signature = '???';
    protected $description = 'Description of the command';

    public function handle ()
    {
        //... code
    }

}

Trying to understand how to structure it. This is pretty much from what I've seen in other examples. But I'm not entirely sure what this does and how this works.

So the Console and the schedule method register the scheduler with the event->monthly() telling the scheduler this is something to run 1st of every month?

And the command class is the logic that is triggered by the scheduler? Is my understanding correct that the command class is where the logic I want to run should live?

    MikeLundahl So the Console and the schedule method register the scheduler with the event->monthly() telling the scheduler this is something to run 1st of every month?

    https://laravel.com/docs/8.x/scheduling#schedule-frequency-options

    MikeLundahl And the command class is the logic that is triggered by the scheduler? Is my understanding correct that the command class is where the logic I want to run should live?

    Yes you can use command, but you can also use Jobs or Invokables:

      luceos Thanks!

      Reading into this, are the Artisan Commands more for Artisan CLI commands you want the scheduler to fire?

      So, is this a correct way of viewing this?
      Commands - Artisan CLI commands to run
      Jobs - Class with logic to run that's added to the queue
      Invokable objects - Class with logic to run that gets executed directly

        MikeLundahl I think the right way to see it is like this:

        • Artisan Command can be executed from CLI/console
        • Jobs are dispatched to the Queue for asynchronous processing
        • Invokable classes (__invoke() method) are isolated tasks/services

        Any of these can or might be triggered from any part of the code as well.

          luceos Ah, thanks!.. That makes sense.

          So I did some reading on it. Looking at the scheduler, it expects a command class, but how do I use a invokable class instead?

          I tried putting my invokable class in the first argument, but that didn't work. I could probably use the invokable class to replace the function in the second argument (like i've seen in another example), but the invokable class I also want to use in another place in the codebase that's not scheduled (that's meant to be triggered manually).

          So would the syntax look something like this?

           (new Extend\Console())
                  ->schedule(CommandClass::class, function (Event $event) {
                      $invokable = new MyInvokableClass()
                      $invokable('myArg')
          
                      $event->monthly();
                  } )

          Is the command class in the first argument needed? Or could I pass null as a parameter?

            MikeLundahl (new Extend\Console())
            ->schedule(CommandClass::class, function (Event $event) {
            $invokable = new MyInvokableClass()
            $invokable('myArg')
            $event->monthly();
            } )

             (new Extend\Console())
                    ->schedule(MyInvokableClass::class, function (Event $event) {
                        $event->monthly();
                    })

            or with Arg:

             (new Extend\Console())
                    ->schedule(new MyInvokableClass('myArg'), function (Event $event) {
                        $event->monthly();
                    })

            But usually you'll resolve the arg from within the __invoke method. Adding such a value from your extend.php is as hardcoded as setting it in the invokable class itself. You can resolve any container (ioc) bound class in the __invoke method as well, like the SettingsRepositoryInterface of Flarum.

              luceos (new Extend\Console())
              ->schedule(new MyInvokableClass('myArg'), function (Event $event) {
              $event->monthly();
              })

              Tried this but I'm getting the error: TypeError: Flarum\Extend\Console::schedule(): Argument #1 ($command) must be of type string

              luceos (new Extend\Console())
              ->schedule(MyInvokableClass::class, function (Event $event) {
              $event->monthly();
              })

              Also tried this without arg and then I get Error: Call to undefined method M\MyExtension\Tasks\MyInvokableClass::getName()

              my class is just a simple class with the __invoke() method.

              class MyInvokableClass {
                 public function __invoke() {
                    //...code
                 }
              
              }

              Does it need to extend something in particular, like Illuminate\Console\Command?

                MikeLundahl if you get errors when using the class string I can only assume the invokable class won't work and you will need a command after all. I hadn't tested it honestly.

                I tried this

                    (new Extend\Console())
                        ->schedule('', function (Event $event) {
                            $myTask = new MyInvokableClass();
                            $myTask('myArg');
                            $event->everyMinute();
                        })

                There are no errors, but it seems to trigger triple times every time I refresh the page. Both the forum and admin page

                  MikeLundahl I would recommend creating a command class and using that with a ::class. The reason your code is now executed is because you are actually instantiating and executing the Invokable class in the registration, this always runs.

                    luceos Thanks!

                    So I followed the documentation, I created a command class that extended \Flarum\Console\AbstractCommand.

                    So I got it to work. My solution was:

                    (new Extend\Console())
                            ->command(MyCommandClass::class)
                            ->schedule('my_command:init', function (Event $event) {
                                $event->everyMinute();
                            }, ['myArg'])

                    And my command class

                    class MyCommandClass extends AbstractCommand {
                       protected function configure() {
                          $this->setName('my_command:init')
                          ->setDescription('do stuff')
                          ->addArgument('myArg')
                       }
                    
                       protected function fire() {
                          //... my logic
                       }
                    }

                    So even if Laravel support different types of scheduled tasks/classes. From my understanding, Flarum only supports running command classes. Could this be correct?

                      luceos I see. Are there any benefits/differences to using the Laravel command instead of Flarum's command?

                        MikeLundahl Laravel makes things simpler, like using the signature property instead of the construct to set arguments etc.