Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: Send slack notification after a scheduled task finished

Tags:

laravel

slack

I need to schedule a few tasks on an application built using Laravel and I would like to send a slack notification after those tasks are finished with the output.

Laravel provides an "after" hook (https://laravel.com/docs/5.8/scheduling#task-hooks) so I can do something like this:

$schedule->command('mycommand')
     ->daily()
     ->after(function () {
         // How can I access the command's name and output from here?
     });

I've tried with $this->output but $this points to App\Console\Kernel and it says Undefined property: App\Console\Kernel::$output. I've also tried to pass a parameter to the closure, but I think I need to specify a type, but I have no idea and the documentation is not very clear.

Anyone has any idea on how to do this?

Thanks in advance!

like image 528
TJ is too short Avatar asked Sep 18 '25 23:09

TJ is too short


2 Answers

Assuming you have this in your command

$this->info('hello');

In your kernel, you can send the output to a temporary file and then read the file and send it

/** @var \Illuminate\Console\Scheduling\Event $command */
$command = $schedule->command('mycommand')
    ->daily()
    ->sendOutputTo('storage/app/logs.txt');

$command->after(function () use ($command) {
    \Log::debug([$command->command, $command->output]);
    \Log::debug(file_get_contents($command->output));
});

You will get

[2019-10-11 13:03:38] local.DEBUG: array (
  0 => '\'/usr/bin/php7.3\' \'artisan\' command:name',
  1 => 'storage/app/logs.txt',
)  
[2019-10-11 13:03:38] local.DEBUG: hello 

Maybe it would be the time to re-open this proposal https://github.com/laravel/ideas/issues/122#issuecomment-228215251

like image 148
Clément Baconnier Avatar answered Sep 20 '25 18:09

Clément Baconnier


Define a macro for the console scheduling event in your app service provider:

namespace App\Providers;

use Illuminate\Console\Scheduling\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
 
class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Event::macro('slackOutput', function (bool $onlyIfOutputExists = false): self {
            return $this->thenWithOutput(
                function ($output) {
                    $level = $this->exitCode === 0
                        ? 'info'
                        : 'error';

                    Log::channel('slack')
                        ->log(
                            $level,
                            $this->getEmailSubject(),
                            [
                                'output' => $output,
                            ]
                        );
                },
                $onlyIfOutputExists
            );
        });
    }
}

Use it like this if you want slack logs even if there's no output:

$schedule
    ->command('inspire')
    ->slackOutput();

Use it like this if you want slack logs only when there is output:

$schedule
    ->command('inspire')
    ->slackOutput(true);

I am on Laravel 9. YMMV.

like image 22
datashaman Avatar answered Sep 20 '25 19:09

datashaman