如何在Laravel 5.4中多次调度具有不同参数的相同作业?

时间:2017-06-16 17:03:40

标签: laravel queue scheduler jobs

Laravel相当新,这是我第一次使用Laravel调度程序和Jobs Queue。

我正在开发一个应用程序,用于从远程api检索数据并将其存储在本地。我有一个包含位置数组的配置文件。每个位置可以具有用于检索数据的不同频率。在我的App \ Console \ Kernel类中,我循环遍历位置数组并安排定期作业来收集该位置的数据。

我创建了一个检索远程数据并保存的作业。作业类接受位置参数。

当我启动调度程序时,它循环遍历位置数组并以正确的次数调度作业。我遇到的问题是,每次我的作业运行时,每次作业运行时都使用位置数组中最后一个的location参数。

如果我的数组中有5个位置,则作业运行5次,但每次使用位置数组末尾的位置参数。

计划

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's 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);

    }
}

作业 - 从构造

接收zip
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();

    }

}

任何人都可以看到我可能出错的地方吗?

我一直在我当地的WAMP环境中对此进行测试。也许我需要在cron实际运行的CentOs服务器上进行测试?

这似乎应该有效。

0 个答案:

没有答案