mardi 10 mars 2020

How to send data from the scheduler to the artisan command in Laravel 5.5

Okay, so I basically need to generate a json file using Laravel's scheduler and a custom artisan command (said list is actually a list of popular cities in our application). So I went ahead and did just that. Here's the definition of my Artisan command:

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Services\PlaceService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;

class CitySearch extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'city:search {--locale=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generates the list of the most popular cities to be used across the application when we need it.';

    private $placesService;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct(PlaceService $placesService)
    {
        $this->placesService = $placesService;
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        App::setLocale( $this->option('locale') );


        $request = Request::create(route('api.search-places'), 'GET', ['maxResults' => 3000, 'isArtisan' => true]);

        $request->headers->set('Accept', 'application/json');
        $request->headers->set('Api-Key', 'aaaaaaaaaaaa');
        // $request->headers->set('Api-Key', '43JSOSH333KSOH555WHO99');
        $request->headers->set('App-client', 'web');

        $response = app()->handle($request);
        $content = json_decode($response->getContent());

        $results = array_map(function($element){

            if($element->type == "City")
                $context = ['an', 'se', 'me'];
            else
                $context = ['se'];



            return ['displayName' => $element->displayName, 'context' => $context];
        }, $content->data);

        print(json_encode($results));



    }
}

Then I went into the scheduler and added the following to have the command run once a week:

namespace App\Console;

use App\Console\Commands\Admin\RedFalcon\PendingTransactionNotificator;
use App\Console\Commands\Admin\RedFalcon\FraudTransactionNotificator;
use App\Console\Commands\CardGenerate;
use App\Console\Commands\Communauto\Stats;
use App\Console\Commands\CPS\Archiver;
use App\Console\Commands\CPS\AutoCasher;
use App\Console\Commands\CPS\Autofixer;
use App\Console\Commands\CPS\Beta\Testers;
use App\Console\Commands\CPS\BNC\EmailFailedBankTransaction;
use App\Console\Commands\CPS\BNC\FeedComposer;
use App\Console\Commands\CPS\BNC\Feeder;
use App\Console\Commands\CPS\BNC\FeedMediator;
use App\Console\Commands\CPS\BNC\FeedReporter;
use App\Console\Commands\CPS\BNC\Parametrizer;
use App\Console\Commands\CPS\Captor;
use App\Console\Commands\CPS\ConfirmationFix;
use App\Console\Commands\CPS\ConfirmationCodeRemoval;
use App\Console\Commands\CPS\DB\RideArchiver;
use App\Console\Commands\CPS\DB\RideFixer;
use App\Console\Commands\CPS\Rider;
use App\Console\Commands\CPS\Test\Resetter;
use App\Console\Commands\CPS\Transactor;
use App\Console\Commands\CPS\Troubleshooting\Experiment1;
use App\Console\Commands\Notifications\ApnFeedbackService;
use App\Console\Commands\RelavelTester;
use App\Console\Commands\UpdateCityPopularity;
use App\Console\Commands\Util\FixBankTransactionTable;
use App\Console\Commands\Util\FixPreauthorizationTable;
use App\Console\Commands\Util\ResetPassword;
use App\Console\Commands\CitySearch;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\Log;

class Kernel extends ConsoleKernel
{

    protected $list;
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        CardGenerate::class,
        Rider::class,
        Autofixer::class,
        Captor::class,
        Transactor::class,
        Archiver::class,
        FeedComposer::class,
        FeedMediator::class,
        Feeder::class,
        Parametrizer::class,
        RideFixer::class,
        RideArchiver::class,
        RelavelTester::class,
        FixPreauthorizationTable::class,
        PendingTransactionNotificator::class,
        FraudTransactionNotificator::class,
        FixBankTransactionTable::class,
        Resetter::class,
        Testers::class,
        Stats::class,
        Experiment1::class,
        FeedReporter::class,
        ResetPassword::class,
        AutoCasher::class,
        ConfirmationFix::class,
        ConfirmationCodeRemoval::class,
        CitySearch::class,
        UpdateCityPopularity::class,
        EmailFailedBankTransaction::class,
        ApnFeedbackService::class
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('city:search --locale=fr')
            ->mondays()
            ->at('14:40')
            ->sendOutputTo(storage_path() . "/app/city-fr.json");

        $schedule->command('city:search --locale=en')
            ->mondays()
            ->at('14:40')
            ->sendOutputTo(storage_path() . "/app/city-en.json");
    }

    /**
     * Register the Closure based commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        require base_path('routes/console.php');
    }
}

Now, this works relatively well... except sometimes it crashes. When that happens, the two json files become filled with error messages instead of the actual data. What I'd like to do is basically save the original list before the command executes and in case something fails, I'd like to output that list into the file and log the error. Right now, everything goes into the file and of course, I get a truckload of errors in my application because the city list is invalid.

Since I'm in Laravel 5.5 I tried using the "before" and "after" hooks (onFailure and onSuccess not available in my version of the framework) and came up with this:

$schedule->command('city:search --locale=fr')
->everyMinute()
->before( function(){ 
    $this->list = json_decode(file_get_contents(storage_path() . "/app/city-fr.json"));
})
->after(function(){
    $test = json_decode(file_get_contents(storage_path() . "/app/city-fr.json"));
    Log::debug($test);
})
->sendOutputTo(storage_path() . "/app/city-fr.json");

So, while I can successfully get the original list from the file before the process begins, in the "after" hook, the file is still empty so there's no way for me to know whether the process failed or not.

Does anyone know how I should go about this? It feels like the solution is right in front of my face, but I'm just missing it.



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire