I can't log anything from my Job's handle method, with the Log facade. Logging from controller or other part of the application with this facade works fine.
I have tried the solution here : Logging not working in laravel queue job, but it does not work with Laravel 6.17, and here : https://stackoverflow.com/a/55206727/10767428 , but it does not affect behaviour in any way.
PHP 7.2
Laravel 6.17
APP_ENV=local
APP_LOG_LEVEL=debug
Laravel runs inside Docker with Alpine image and other stuff unrelated
Here is my job :
class MyJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function handle()
{
Log::warning("HI");
}
}
The Job is correctly handled when I dispatch if, but nothing shows up in my storage/app/logs/laravel.log.
This file and the entire folder storage has 777 permissions.
I use "single" driver in config/logging.php :
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
],
Any ideas?
EDIT 07/17/2020
As requested, here is my config.horizon.php :
https://pastebin.com/jkQLcDKF
EDIT 07/20/2020
I can log from the same job when I use dipatchNow method to call it, instead of dispatch one. Any ideas why ?
If your queue is running on Supervisor, your log would be in the Supervisor logs. Share your queue/supervisor configuration if you're not able to find it.
You could also check your docker logs as well.
If anyone else is having issues, Horizon has to be restarted when changes are made to the jobs. Otherwise, the job that runs will not reflect your code changes.
This is regardless of the environment. That's why it's a good idea to restart horizon when you re-deploy to the server.
Related
I am trying to run a time consuming script in the background with Laravel 8, but cant quite get it to work. I try to follow the docs from here https://laravel.com/docs/8.x/queues in combination with the tutorial found here: https://learn2torials.com/a/how-to-create-background-job-in-laravel
As per docs, I should run the following commands to get strateted with Queue/jobs in Laravel
php artisan queue:table
php artisan migrate
Then we should create our Job with the following command
php artisan make:job TestJob
In App\Jobs\ is our newly created job-file: TestJob.php
Again following the docs, I should put my time consuming script/code in the handle() method of TestJob.php. I have written the following code in handle() for test purposes:
public function handle()
{
//Do some time-consuming stuff
sleep(30);
}
Next, according to the docs, we should dispatch our job with the following line of code TestJob::dispatch(), anywhere in our app, so for test purposes, I put this line directly into our routes file, like this:
Route::get('/', function () {
//Run this job in the background and continue
\App\Jobs\TestJob::dispatch();
//After job is started/Queued return view
return view('welcome');
});
That should be it, as I understand from the docs, but it is not working as I expected. The code in handle() gets executed, but the return view('welcome'); is executed AFTER the the job is completed.
I was expecting the script to be executed and while running in the background the next line of code will be executed. How can I make it run in the background so the user do not have to wait for the script to finish?
I have googled a lot and according to the tutorial linked to earlier, I should have the following line: QUEUE_DRIVER=database in my .env file. I have sat this, and also sat it in Config\queue.php with the following line: 'default' => env('QUEUE_CONNECTION', 'database'),, but still same result
I also found the following solution for Laravel 5 here on SO (link), where there is suggested that we also should run the following code to get it to work: php artisan queue:listen, but its the same result again
Any help would be much appreciated!
By default the .env file has QUEUE_CONNECTION=sync.
Meaning, the sync connection uses the main thread for the execution of tasks. Hence, it has to first complete before moving on to the next line of code.
To make tasks run in the background so that your main application thread won't block and you can serve your client requests more quickly, try using a different connection i.e database.
To do this, simply change QUEUE_CONNECTION=database in your .env file.
You may run php artisan queue:listen on your local computer set-up to process tasks as they come in.
NOTE: On the production server, it may be more convenient to set-up something more robust to automatically restart your processes if they fail. Supervisor Configuration
I recently hosted a laravel project (for a customer) on shared hosting, after failed attempts to get access to the server via ssh I contacted the host who informed me that ssh service was not available for my customers hosting plan, that means I have no access to terminal and can't use artisan. I know how to write a php script that will create sql tables but just before that I was wondering if theres a shortcut to this with laravel since the migrations(tables) are already defined. What I want is like to create a route project.com/run_migrations to do the job! Thanks in advance
You can easily create a small Artisan script within PHP like this:
Artisan::call('migrate');
This equals php artisan migrate. Use it anywhere you want to run your migrations.
If you are in production mode (if APP_ENV=production inside your .env file) then you would have to force the migration in case you want to allow to make changes. You can do it as follows:
Artisan::call('migrate', ["--force" => true ]);
This equals adding the --force flag a la php artisan migrate --force.
To answer your specific question though, create a route like this:
Route::get('/run-migrations', function () {
return Artisan::call('migrate', ["--force" => true ]);
});
If you are interested in creating a web installer, you might be interested in this package:
https://github.com/Froiden/laravel-installer
Check out the code to see how he handles migrations and seeds etc.
Original Post
Good evening folks. I have a laravel setup and I'm trying to have a cronjob execute a php function to a file within the laravel project directory.
I am getting class and name space errors when I try to do something like this:
<?php
require_once('../laravel/app/Http/Controllers/NotificationsController.php');
and then calling the processQueuedNotifications() function.
This of course gives me errors, what is the correct way to call my function within the laravel directory? I need to call this function as this function has all the correct namespaces and extended controllers necessary to execute the function properly.
Update 1:
Thanks to #michael, I've been made aware of a component in Laravel called commands.
So I ran this code:
php artisan make:console processQueuedNotifications
and it created some files in the console directory.
Currently exploring on what to do next.
After checking out the Events class which the kernel.php file makes use of, I noticed that this class provides an easy to use interface for me to create cron jobs on the fly. Am I correct in think so?
I notice there is not function to run a cron job every minute, is it safe to edit the Events class file without it being overwritten by future make:console commands, or laravel updates?
I saw this code in the kernel.php file:
$schedule->command('inspire')
->hourly();
So is this the place you wanted me to add my function? as I notice that the inspire function is something automatically created for me to understand what's going on?
So I would write,
$schedule->command('processQueuedNotifications')
->everyMinute();
//Providing it's safe to edit the Event's class or figure out a clean way of doing so without my code being deleted in the future on Laravel updates.
A very convenient way is to use laravels console component. You can create a new command by issuing
php artisan make:console
And find it thereafter in your app/console directory. Make sure to enable the command in the Kernel.php file once created.
Simply call your class or whatever you want to run via cron from inside the command. The console command itself is callable via cli just as you would run one of laravels php artisan ... commands. You can set this in the file created for you. For example, you can then call the file from everywhere you want with
/usr/bin/php /path/to/file/artisan my:command
You can set options and arguments if you need to.
Here's the documentation: http://laravel.com/docs/5.0/commands / http://symfony.com/doc/current/components/console/introduction.html
There's an array in kernel.php you need to register your class (include the namespace) in. After that it is callable via cli. For a start, have a look on arguments and options you can initialize in case you need to make different requests on your controller class. (The filename you have chosen for your console command, is an argument. You can make them required or optional for your own commands. )
Within your file, you can create them by simply creating an array in the appropriate method with these values:
[$name, $mode, $description, $defaultValue]
have a look at the docs or Jeffrey's laracasts, they are very good.
To only call your class from the console command, it's enough to name your command in the above section of the file and call you controller like
(new namespace\controller)->method();
What you can do in your code, after your update, 2 choices :
Dispatching directly the command from your code using the Bus facade
first import it using the
use Illuminate\Support\Facades\Bus;
then in your code
Bus::dispatchNow(new YourCommandClass);
(don't forget to import your command class)
Dispatch it for queue process using the same bus facade:
(still importing the same way)
Bus::dispatch(new YourCommandClass);
(Note that in that case, you'll need to have the following command run by your cron job :
php artisan queue:listen
it can handle several options such as the --tries=X where is is the number of tries etc
Generally speaking, you can get more info from commands typing php artisan my:command -h
I have an event that is fired when I receive certain notifications. I want to Queue the event so that they aren't all fired at the same time but are Queued up as I receive them and then fired after the previous event completes. I want to know the best way to do this.
Edit: Just for anyone in the future, setting up the database Queue driver is very straightforward and simple. You run the php artisan queue:table and change the driver to 'database'. My problem was that my app wasn't recognizing my QUEUE_DRIVER setting in my .env file for some reason.
Laravel 5 has it's own way of dealing with queued jobs, but you can still use the options that were available in Laravel 4. I've personally been curious as to how it all works and just threw together a blank project and ran a couple of queued jobs with a little help from the docs so this may not be a full answer but I hope this helps you on your way.
First you will want to set your config to use the database queue driver, this can be done in config/queue.php or for me it was a matter of going to the .env file and doing this: QUEUE_DRIVER=database.
Then you want to set up the database table to hold the queued jobs, you can do this by running an artisan command: php artisan queue:table this will create the migration so then you need to create the table by running php artisan migrate and then you'll have your jobs table in your DB.
Following that, you'll want to set up a queued job which come in the form of Commands. For example I'll set up a job that writes some text to the log file. You can create jobs or commands using an artisan command, here's what I did to create a command: php artisan make:command WriteToLog --queued. And here's what my command class looks like after adding a little code to get it to write to the log file...
app/Commands/WriteToLog.php
use App\Commands\Command;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldBeQueued;
class WriteToLog extends Command implements SelfHandling, ShouldBeQueued {
use InteractsWithQueue, SerializesModels;
protected $secs;
/**
* Create a new command instance.
*
* #return void
*/
public function __construct($secs)
{
$this->secs = $secs;
}
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
\Log::info('Writing to the log in ' . $this->secs);
}
}
After creating a command, to test it out I wrote a route in my routes file ...
app/Http/routes.php
Route::get('/', function(){
// some time to delay the job
$fiveSecs = \Carbon\Carbon::now()->addSeconds(5);
$tenSecs = \Carbon\Carbon::now()->addSeconds(10);
// adds job to queue
Queue::later($fiveSecs, new App\Commands\WriteToLog('5 secs'));
Queue::later($tenSecs, new App\Commands\WriteToLog('10 secs'));
return 'All done';
});
Before we hit the route we want to listen for any jobs in order to process them, just run php artisan queue:listen then you can go to your browser to the route, after hitting the route in my browser the console shows
$ php artisan queue:listen
Processed: Illuminate\Queue\CallQueuedHandler#call
Processed: Illuminate\Queue\CallQueuedHandler#call
And if I check my log file I see the following:
[2015-05-19 19:25:08] local.INFO: Writing to the log in 5 secs
[2015-05-19 19:25:10] local.INFO: Writing to the log in 10 secs
Not exactly 5 and 10 seconds apart but hopefully you get the idea!
For me this is really just the tip of the iceberg and queued jobs are something very powerful in laravel, I highly recommend checking out the docs here: http://laravel.com/docs/5.0/queues and here: http://laravel.com/docs/5.0/bus
You can also fire events from your queued jobs or queue an event handler, see here for more details: http://laravel.com/docs/5.0/events#queued-event-handlers
Laravel makes queues pretty straightforward, but a bit long to explain fully here. Check out these guides:
If you are using forge, it is really painless:
https://mattstauffer.co/blog/laravel-forge-adding-a-queue-worker-with-beanstalkd
If you aren't using forge, it is still pretty ok: http://fideloper.com/ubuntu-beanstalkd-and-laravel4
I have a quite simple job that runs on Laravel 4 FW. When the queue driver is set as "sync", it works fine. But, when I set it to 'beanstalkd', it simply DOESN'T RUN! I already ran the artisan command php artisan queue:listen and php artisan queue:work but none seems to work.
When I type php artisan queue:work it gives me the following error:
[ErrorException]
Trying to get property of non-object
Here's my beanstalkd connection configuration:
'beanstalkd' => array(
'driver' => 'beanstalkd',
'host' => 'localhost:11300',
'queue' => 'default',
),
I've already tried to set the 'host' as a '0.0.0.0' and '127.0.0.1'.
Any ideas why isn't working?
EDIT:
Here's some piece of code of the fire() method.
static public function fire($job, $data)
{
ini_set('memory_limit', '512M');
set_time_limit(300);
$hotel_ids = $data['hotels'];
self::$client = $data['client'];
self::$currency = $data['currency'];
// A list of paths to the generated PDFs
$paths = array();
foreach ($hotel_ids as $list) {
$hotels = Hotel::whereIn('id', $list)->orderBy('name', 'asc')->get();
$paths[] = self::makePDF($hotels);
}
#self::sentPDFs($paths);
$job->delete();
}
EDIT 2:
The job itself run on sync driver, though my thoughts are on beanstalkd. I installed the beanstalkd console, a way of view the jobs and the queue grafically. Here's another interesting thing: the job is queued, he gets in the 'ready' stage then goes back! And that keeps going on! He gets in ready stage, e then (I believe) happens some sort of error and it get's out!I don't know what is the error, since it doesn't appear in SYNC drive.
Another interesting thing: if I remove all code from the fire method and lets only, for example, Log::error('Error'); it happens the same exact thing!
Have you installed Pheanstalk? It's required to use beanstalkd with the Laravel queue system.
Check your firewall configuration. I added port 11300 to the firewall tables and it works!