I am using the Laravel scheduler to run a job and if the job fails I want to write to the log and get sent an email. However as soon as I set it up even though the job was running fine I started getting emails and output in the log so for some reason Laravel is treating the job as if it's failed when it hasn't. Also if I look at the job in Telescope the status just stays on pending and never shows as complete or failed. I am using sync as my queue driver.
Here is my kernel.php file:
<?php
namespace App\Console;
use Log;
use App\Company;
use App\Jobs\ProcessPayments;
use App\Jobs\ProcessCompanyTiers;
use Illuminate\Console\Scheduling\Schedule;
use App\Jobs\ProcessPartialDiscountPayments;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
\App\Console\Commands\ProcessPartialDiscountPayments::class
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->job(new ProcessPartialDiscountPayments)
->onSuccess(function () {
Log::info('ProcessPartialDiscountPayments scheduled task successfully ran');
})
->onFailure(function () {
Log::info('ProcessPartialDiscountPayments errored and did not complete');
})
->emailOutputOnFailure(config('app.webmaster_email'));
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
/**
* Get the timezone that should be used by default for scheduled events.
*
* #return \DateTimeZone|string|null
*/
protected function scheduleTimezone()
{
return 'Europe/London';
}
}
And here is the job file:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Jobs\ProcessCompanyPayment;
use App\{ Company, DiscountCode };
use Log;
use Carbon\Carbon;
class ProcessPartialDiscountPayments
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $code_datetime;
protected $datetime_to;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
Log::info('Running ProcessPartialDiscountPayments');
$datetime = Carbon::now();
$this->code_datetime = $datetime->format('Y-m-d H:i');
$this->datetime_to = $datetime->format('Y-m-d H:i:s.v');
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$discount_codes = DiscountCode::whereRaw("left(convert(varchar(20), ValidTo, 120), 16) = '".$this->code_datetime."'")->get();
Log::info('Found '.$discount_codes->count().' discount codes');
if(!empty($discount_codes)) {
foreach($discount_codes as $discount_code) {
if($discount_code->companies->count() > 0) {
foreach($discount_code->companies as $company) {
$active_code = $company->discount_code($company->balance_at($this->datetime_to), $this->code_datetime);
if($active_code && $active_code->Id == $discount_code->Id) {
Log::info('Processing #'.$company->Id.': '.$company->Name);
ProcessCompanyPayment::dispatch($company, $this->datetime_to);
}
}
}
}
}
}
}
Here is the log entries that get generated when it runs:
[2019-12-19 12:32:03] local.INFO: Scheduler running
[2019-12-19 12:32:03] local.INFO: Running ProcessPartialDiscountPayments
[2019-12-19 12:32:03] local.INFO: Found 0 discount codes
[2019-12-19 12:32:03] local.INFO: ProcessPartialDiscountPayments errored and did not complete
Currently $discount_codes is always empty so the expected output should be that the handle function just writes to the log saying it hasn't found any and then the job completes.
Related
I want to run a task schedule at daily and I am trying execute a function which will initialize the value in the database.But terminal showing error while running php artisan schedule:work
2022-11-23 06:25:00 Running [Callback] ................................................................................................ 899ms FAIL
The code is
<?php
namespace App\Console;
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
$schedule->call(function () {
$schedule = schedules::find(1);
$schedule->endTime = "00:00:00";
$schedule->save();
}->daily();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
When adding an item to the queue, for some reason the handle method is not being called.
The Log entry in __construct is appearing but when attempting to log in handle(), nothing appears.
The method i'm using to dispatch is ProcessImport::dispatch($path, $task->task_id);
My queue service is configured to use Redis, and redis is storing all the data accordingly.
I am using Laravel 8. What could be wrong?
<?php
namespace App\Jobs;
use App\Models\Tasks;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Http\Controllers\Products\Products;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Queue;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Queue\Events\JobProcessed;
use Throwable;
class ProcessImport implements ShouldQueue, ShouldBeUnique
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $file_path;
protected $response;
protected $task;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($path, $task_id)
{
Log::info("Importing products (construct)");
$this->task = Tasks::where('task_id', $task_id)->first();
$this->file_path = $path;
Log::info('Importing ' . $path);
}
private function getFilePath() {
return $this->file_path;
}
/**
* Handle a job failure.
*
* #param \Throwable $exception
* #return void
*/
public function failed(Throwable $exception)
{
$this->task->failed($exception->getMessage());
}
/**
* Get the cache driver for the unique job lock.
*
* #return \Illuminate\Contracts\Cache\Repository
*/
public function uniqueVia()
{
return Cache::driver('redis');
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Log::info("Importing products (handle)");
$this->task->start();
$products = new Products();
$products->importProductsFromCSV($this->getFilePath());
$this->task->success();
Log::info("End of importing products..");
}
}
You've just pushed the jobs onto the queue but haven't started a worker to process them. You can run the worker with:
php artisan queue:work
I'm working with one of my Laravel 8 API project's that I've built where a user is able to add a domain to their account. The domain needs to be crawled to obtain expiration dates etc and is available in the user's account.
This process takes some time and so I've extracted the logic that fetches the domain data into a job called DomainExpiryChecker.
When a new domain is added, a job is dispatched, but may not execute straight away, and in some cases the user may even delete the domain before the job runs.
For some reason, even after dispatching my job after a record has been made, I'm getting the following failed job error and I'm not sure what I'm missing:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Models\Domains]
My controller where the job is dispatched resembles the following:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Models\User;
use App\Models\Domains;
use Carbon\Carbon;
use App\Jobs\DomainExpiryChecker;
class DomainsController extends Controller
{
/**
* Instantiate a new DomainsController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Add a new domain
*
* #param Request $request
* #return Response
*/
public function add(Request $request)
{
$domain = new Domains();
$domain->domain = '';
$domain->crawled = 'pending';
$domain->has_valid_ssl = false;
$domain->user_id = Auth::id();
$domain->save();
// on-demand
if ($domain) {
DomainExpiryChecker::dispatch($domain)->onQueue('on-demand-runs-now');
}
// everything went okay!
return response()->json(['success' => true, 'message' => "Added $domain_name successfully, please allow between 24 and 48 hours for crawling"], 201);
}
}
Whilst my job looks like the following:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Client;
use App\Models\Settings;
use App\Models\Domains;
use Carbon\Carbon;
class DomainExpiryChecker implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The domain instance.
*/
protected $domain;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($domain)
{
$this->domain = $domain;
}
/**
* Get single domain
*
* #return object
*/
public function getDomain($domain)
{
$domain = Domains::where('id', $domain['id'])
->first();
return $domain;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$updatableDomain = $this->getDomain($this->domain);
if (!$updatableDomain) {
return;
}
// stuff happens here
}
}
What am I missing, I'm sure it's just one thing.
I have created a very basic queue job:
<?php
namespace App\Jobs;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class FailingJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
// nothing
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// nothing
}
/**
* Called when the job fails
*
* #param Exception $exception
*/
public function failed(Exception $exception) {
// nothing
}
}
and I dispatch it like so: FailingJob::dispatch();. This works fine.
Now I am purposefully adding "bugged" code in order for the job to fail, but instead of gracefully making the job fail,
I get the following exception:
Serialization of 'Closure' is not allowed.
I'm not sure where this is coming from, because this job is basically empty. I would like to use the failed() function in order to handle failures, but I can't even do that because this exception gets thrown when the job fails.
For reference, this is the code I use to make the job fail:
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
xxxxxx
// ^ This will make the job fail
}
I´m trying to create $schedule job in Laravel to read Email with PHP IMAP package. If I go to route, package read email and does all correctly, but need to do this every 5 minutes.
I create a new command class and add this
use Illuminate\Http\Request;
class ReadMail extends Command implements SelfHandling {
protected $name = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* #return void
*/
public function fire()
{
$request = Request::create($this->option('App\Http\Controllers\MailController#index'), 'GET');
$this->info(app()['Illuminate\Contracts\Http\Kernel']->handle($request));
}
In kernel
protected $commands = [
'App\Console\Commands\ReadMail',
];
protected function schedule(Schedule $schedule)
{
$schedule->call('read:mail')
->everyFiveMinutes();
}
I'm not sure if this code it´is correct, but does not work properly. Any idea about it?
Thank in advance for your help.
UPDATE
I launch this
php artisan read:mail and return
Argument 1 passed to Illuminate\Console\Application::add() must be an instance of Symfony\Component\Console\Command\Command, instance of App\Commands\ReadMail given
The code of ReadMail class
<?php namespace App\Commands;
use App\Commands\Command;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Http\Request;
class ReadMail extends Command implements SelfHandling {
protected $signature = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the command.
*
* #return void
*/
public function fire()
{
$request = Request::create($this->option('App\Http\Controllers\MailController#index'), 'GET');
$this->info(app()['Illuminate\Contracts\Http\Kernel']->handle($request));
}
}
UPDATE 2: SOLVED - ALL CODE
Kernel
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel {
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
'App\Commands\ReadMail',
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('read:mail')
->everyFiveMinutes();
}
}
ReadMail
<?php namespace App\Commands;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Http\Request;
use Illuminate\Console\Command;
use App\Http\Controllers\MailController;
class ReadMail extends Command implements SelfHandling {
protected $name = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
MailController::index();
}
}
MailController
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use PhpImap\Mailbox as ImapMailbox;
use App\Models\Escalas;
class MailController extends Controller {
public static function index()
{
$mailbox = new ImapMailbox('{imap.gmail.com:993/imap/ssl}INBOX', '', '','');
$mailsIds = $mailbox->searchMailbox('UNSEEN');
if(!$mailsIds) {
die('Mailbox is empty');
}
$mail=[];
foreach ($mailsIds as $index=>$data){
$mail[]=$mailbox->getMail($mailsIds[$index]);
Escalas::insert([
['' => $mail[$index]->textPlain,
'' => $mail[$index]->date,
''=>$mail[$index]->subject,
''=>$mail[$index]->fromName,
''=>$mail[$index]->fromAddress,
''=>$mail[$index]->toString],
]);
}
}
}
Try changing
protected $name = 'read:mail';
with protected $signature= 'read:mail';
in your ReadMail class and then run in Kernel like this
$schedule->command('read:mail')->everyFiveMinutes();
Check whether your scheduled tasks are set up properly (see docs for Laravel 5.0) Make sure you've added a cronjob to trigger Laravel's scheduled commands. To check you cronjobs are running, look for a file like /logs/crond.log. When opening this file, you should see lines showing at what times this ran. This is the command that triggers Laravel's scheduled jobs.
If all that is correct, then try running your command via your terminal on localhost to check the command is all set. This should reveal any problems with the command setup. Your functionality itself seems allright, since you mentioned everything works when triggered via a route.