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);
}
}
作业 - 从构造
接收zipclass 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服务器上进行测试?
这似乎应该有效。