How do I schedule the same job with different parameters multiple times in Laravel 5.4?

Quite unexpected for Laravel and this is the first time I've worked with the Laravel scheduler and the Queue service.

I am working on an application to fetch data from a remote api and store it locally. I have a config file with an array of locations. Each location can have a different frequency for retrieving data. In my App \ Console \ Kernel class, I iterate over an array of locations and schedule a repeat job to collect data for the location.

I created a job to retrieve deleted data and save. The job class takes a location parameter.

When I start the scheduler, it goes through the location array and dispatches the job the correct number of times. The problem I am facing is that every time my job is done, every job uses the location parameter from the last one in the locations array.

If I have 5 locations in my array, the job runs 5 times, but each time it uses the location parameter that was at the end of my locations array.

Scheduler

class Kernel extends ConsoleKernel
{

    protected $job;
    protected $queue;
    protected $zip;
    protected $locations;
    protected $location;
    protected $name;
    protected $job_interval;

    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $this->locations = config('weather-app.locations');

        foreach(  $this->locations as $this->name => $this->location ){

            //print_r($location);

            $this->job_interval = (is_null($this->location['interval']) ? config('weather-app.default_interval') : $this->location['interval']);


            if( $this->validateInterval($this->job_interval)){

                //$this->queue =
                $this->job = (new GetWeatherDataByZip($this->location['zip'])); //->onQueue((string)$this->location['zip'] );

                Log::info('Dispatching job for location: ' . $this->location['zip']);

                $schedule->call(function() {
                    dispatch($this->job);
                })->cron($this->job_interval);

            } else {

                $log_msg = 'Failed to initiate new data retrieval schedule for location ' . $this->name . ' - ' . $this->location['zip'] . ' - Invalid interval format';
                Log::error($log_msg);

            }

        }

    }

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

    private function validateInterval($job_interval){

        $data = [
            'job_interval' => $job_interval
        ];

        $cron_regex = "/^(((([\*]{1}){1})|((\*\/){0,1}(([0-9]{1}){1}|(([1-5]{1}){1}([0-9]{1}){1}){1}))) ((([\*]{1}){1})|((\*\/){0,1}(([0-9]{1}){1}|(([1]{1}){1}([0-9]{1}){1}){1}|([2]{1}){1}([0-3]{1}){1}))) ((([\*]{1}){1})|((\*\/){0,1}(([1-9]{1}){1}|(([1-2]{1}){1}([0-9]{1}){1}){1}|([3]{1}){1}([0-1]{1}){1}))) ((([\*]{1}){1})|((\*\/){0,1}(([1-9]{1}){1}|(([1-2]{1}){1}([0-9]{1}){1}){1}|([3]{1}){1}([0-1]{1}){1}))|(jan|feb|mar|apr|may|jun|jul|aug|sep|okt|nov|dec)) ((([\*]{1}){1})|((\*\/){0,1}(([0-7]{1}){1}))|(sun|mon|tue|wed|thu|fri|sat)))$/";

        $rules = [
            'job_interval' => [
                'required',
                'regex:' . $cron_regex
            ]
        ];

        return $this->app['validator']->make($data, $rules);

    }
}

      

Work - gets zip from constructor

class GetWeatherDataByZip implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $zip;
    protected $weather_client;
    protected $weather_data;
    public $tries;
    public $timeout;
    public $retry_after;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct( $zip=NULL )
    {

        $this->zip = $zip;

        /**
         * The number of times the job may be attempted.
         *
         * @var int
         */
        $this->tries = config('weather-app.weatherApi.maxTries');;

        /**
         * The number of seconds the job can run before timing out.
         *
         * @var int
         */
        $this->timeout = config('weather-app.weatherApi.timeOut');

        /**
         * The number of seconds between failed job attempts.
         *
         * @var int
         */
        $this->retry_after = config('weather-app.weatherApi.retryAfter');

    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {

        if(is_null($this->zip)){

            throw new Exception('Missing required input parameter: zip.');

        }

        Log::info('Starting job for location ' . $this->zip);

        $weather_client = new Client();

        $endpoint = config('weather-app.weatherApi.endpoint')
            . '?units=' . config('weather-app.weatherApi.units')
            . '&' . config('weather-app.weatherApi.lookupParam') . '=' . $this->zip;

        try {

            $response = $weather_client->request('GET', $endpoint . '&' . config('weather-app.weatherApi.keyParam') . '=' . config('weather-app.weatherApi.key'), ['allow_redirects' => false, 'http_errors' => true] );
            $response_body = json_decode($response->getBody());
            $this->save($response_body);

        } catch (ClientException $error) {

            $response = $error->getResponse();
            $response_code = $response->getStatusCode();
            $response_reason = $response->getReasonPhrase();

            switch(substr($response_code,0,1)){

                case '3':
                    // Do something unique with Redirect Errors
                    $error_type = 'REDIRECT';
                    break;

                case '4':
                    // Do something unique with Client Errors
                    $error_type = 'CLIENT';
                    break;

                case '5':
                    // Do something unique with Server Errors
                    $error_type = 'SERVER';
                    break;

            }

            $log_msg = $error_type . ' ERROR: ' . $response_code . ' - ' . $response_reason . ' for request ' . $endpoint . ' - Attempt ' . $this->attempts() . ' of ' . $this->tries . ' - Retry in ' . $this->retry_after . ' seconds.';
            Log::error($log_msg);


            /**
             * Retry the job.
             *
             * @return void
             */
            if( $this->attempts() < $this->tries ) {

                $this->release($this->retry_after);

            } else {

                //$this->delete();
                $log_msg = 'ABORTING FAILED JOB for request ' . $endpoint;
                Log::error($log_msg);
                abort($response_code, $log_msg);

            }

        }

    }

    /**
     * Save the data.
     *
     * @return void
     */
    private function save($data) {

        $weather_data = new WeatherDataModel;
        $weather_data->name = $data->name;
        $weather_data->zip = $this->zip;
        $weather_data->conditions = $data->weather[0]->description;
        $weather_data->conditions_short = $data->weather[0]->main;
        $weather_data->pressure = $data->main->pressure;
        $weather_data->temperature = $data->main->temp;
        $weather_data->wind_direction = $data->wind->deg;
        $weather_data->wind_speed = $data->wind->speed;
        $weather_data->humidity = $data->main->humidity;
        $weather_data->save();

    }

}

      

Can anyone see where I might be going wrong?

I tested this on my local WAMP environment. Perhaps I need to test this on our CentOs server where cron is running?

It seems like it should work.

+3


source to share





All Articles