I have such function in my trait:
public function cupPlayMatch(Season $season, $round_id)
{
foreach($season->cups as $cup)
{
$this->cupPlay($cup, $round_id);
}
}
And second cup isstarting playing when first cup finished. How I can start playing all my cups simultaneous?
For the most part, PHP is "synchronous", that means that you theoretically can't make "simultaneous calls" to any function.
However, some workarounds exist to make this work.
PHP is a script language. So when you launch this in your console:
php -r "echo 'Hello World';"
A PHP process is launched, and anything that happen in this process is executed synchronously.
So the solution here, is to launch various PHP processes in order to be able to run functions simultaneously.
Imagine an SQL table where you put all the functions that you want to execute simultaneously. You could then run 10 php processes that would actually work "at the same time".
Laravel provides a solution to this problem out of the box. And as #Anton Gildebrand mentioned it in the comments, it's called "Queues".
You can find the documentation here: https://laravel.com/docs/5.5/queues
The laravel way of doing it, is to create "jobs". Each Job represents a function that you want to execute. Here, your Job would be cupPlay.
Here is the basic example of a job copy pasted from the documentation:
<?php
namespace App\Jobs;
use App\Podcast;
use App\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $podcast;
/**
* Create a new job instance.
*
* #param Podcast $podcast
* #return void
*/
public function __construct(Podcast $podcast)
{
$this->podcast = $podcast;
}
/**
* Execute the job.
*
* #param AudioProcessor $processor
* #return void
*/
public function handle(AudioProcessor $processor)
{
// Process uploaded podcast...
}
}
When you'll have configured your worker driver to run your queues, you'll just need to launch:
php artisan queue:work --queue=high,default
from the command line and it will execute your tasks.
And you can execute as many workers as you want, depending on your needs...
I hope this helps!
Related
I am implementing Queue JOBS, in my Laravel Project for the first time. But I am facing some difficulties on it, as after php artisan queue:work, noting is showing on the terminal.
Let Me describe, the procedure I have tried.
My Controller Function, from where I am trying to fire the Job Queue:
use App\Jobs\InitiateRecharge;
/
/*** Other Codes are here....
/
public function testQueueJob(){
InitiateRecharge::dispatch(1)->onQueue('initrecharge');
return 1;
}
My JOB Queue Class:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class InitiateRecharge implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $reportid;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($reportid)
{
$this->reportid = $reportid;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
sleep(10);
\Log::info('hello....');
}
}
I have also migrated the jobs table, and rows are also getting inserted on that.
It's is not giving any error, but the Job expected output is also not coming .. and in the terminal noting getting changed.
Please, anyone, help me
Thank You in advance :)
try php artisan queue:listen --tries=1
I am writing Laravel json api using MySQL. What I am trying to do, is whenever user creates record, I want to perform some operation on this record every 24 hours, until some changes are made by admin on this record. So averagely this job will be repeated 10-15 times. this is my job:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Http\Models\Orders\RoadOrder;
class RoadOrderEprirationHandler implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
protected $order_id;
public function __construct($order_id)
{
$this->order_id = $order_id;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$order = RoadOrder::findOrFail($this->order_id);
//do some tasks and if I need to run this cycle again :
$roadOrderEprirationHandler = new RoadOrderEprirationHandler($order->id);
$roadOrderEprirationHandler->dispatch($order->id)->delay(now()->addHours(24));
}
}
So as you can see, I initiate job after previous job was finished if admin didn't modified record and I need to run cycle again. after several cycles, I won't run job again, so it will be finished.
My question:
Is some problem in this implementation? maybe I am doing something wrong or maybe there may occur some type of memory leak (because I create job inside job again and again). I can write this but I need to be sure that this implementation doesn't leads to some type of bugs or errors.
Why don't create a separate table in your DB for that purpose?
You can keep order_ids with status (checked by admin / not checked). Or just put new order_id there and delete it after admin check. So you will only use your jobs to see is there any unchecked ids. Or some kind of that.
I think this approach is more predictable and less buggy.
I am developing a laravel 5.7 application.
I have created a command that should setup my database:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
class TestSetupCommand extends Command
{
protected $signature = 'test:data';
protected $description = 'Basic Setup for Test Data';
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
Artisan::call('migrate:refresh', ['--seed' => '']);
Artisan::call('basis:cc');
Artisan::call('tick:exchange');
$this->info("DB freshly setup: DONE");
$this->info("Coin: DONE");
$this->info("Exchange Scrapped: DONE");
}
}
My problem is that each command takes several minutes to run through. In total it costs me 25 minutes to fill the whole database with data.
I would like to run the commands only for 1 minutes each and kill them afterwards.
Any suggestions how to accomplish this within my laravel command?
I think the best way to do this is to extract these commands into background job. This artisan command then becomes code to queue up that new job (or jobs).
Why? It's very easy to configure jobs to timeout after x amount of time, by overriding a value like so:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* The number of seconds the job can run before timing out.
*
* #var int
*/
public $timeout = 120;
}
Also, why are you refreshing the database? That seems.... like a crazy idea unless this is purely an analytics platform (no user data at all). It's probably a bad thing if that refresh command times out - you may look into job chaining so that the refresh command is guaranteed to succeed, then the other commands (new jobs now) have set timeouts.
I'm using database driver to queue my jobs.
I need to call an artisan command from a queued Job and when the Job has finished I need to remove it from the queue.
This is my controller's code where I add the job in the queue
dispatch((new SendNewsletter())->onQueue('newsletter'));
This is my queued Job
<?php
namespace App\Jobs;
use App\Console\Commands\Newsletter;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class SendNewsletter implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
app()->make(Newsletter::class)->handle();
}
}
The artisan command I need to call is App\Console\Commands\Newsletter
and when the Job ends, this should remove it from the queue.
This is AppServiceProvider class
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
Queue::after(function ($event) {
if ($event->job->queue == 'newsletter') {
$event->job->delete();
}
});
}
The Job is added correctly to the database queue and when I run php artisan queue:work the job is called multiple times endless.
seems that Queue::after's callback is never called.
any idea what am I missing ?
Probably your job fails and it is added to queue trying to finsh the work correctly. Try calling the command in your job like this
\Artisan::call('your:command');
Instead of:
app()->make(Newsletter::class)->handle();
Where "your:command" is the command name, that you gave in the command class:
protected $signature = 'email:send {user}';
I have a job to send emails when the user registers in the application.
SendWelcomeEmail.php
<?php
namespace App\Jobs;
use App\Jobs\Job;
use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendWelcomeEmail extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $user;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* #return void
*/
public function handle(Mailer $mailer)
{
$user = &$this->user;
$message = sprintf('Hello %s', $user->name);
$mailer->raw($message, function ($m) use ($user){
$m->from('lucas.nuck#gmail.com', 'Lucas Lopes');
$m->to($user->email, $user->name);
});
}
}
I would like to create a job to execute the php artisan queue: work command every minute to send the emails that are in the queue.
Easiest way would be to set up Supervisor.
https://laravel.com/docs/5.4/queues#supervisor-configuration, it will automatically restart your queue:work process if it fails.
To solve the confusion for you:
In app/Console/Kernel.php file, inside the schedule function you would add a command that you want to be ran at a specific interval. An example would be :
$schedule->command('SendFailedLoginsReport')->weekly()->mondays()->at('03:00');
On your server, you can add your cron like this
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
This Cron will call the Laravel command scheduler every minute
You are wanting to run the queue daemon, not run a command. You need to do this within your server environment, not using laravels scheduled commands.
You could use something like Linux's screen to place your command in.
This will consinuiously poll your queue server for new jobs, then process them.