I'm trying to use commands so I can queue them because of a bunch of requests that will take 30-90 seconds to complete. The only issue is that the command is not returning data to my controller like I hoped it would, instead, all I'm getting is a convenient (sarcasm) "null". Here's some code snippets from my files, and thanks for any help!
HomeController
class HomeController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Show the application dashboard to the user.
*
* #return Response
*/
public function index()
{
var_dump($this->dispatch(new \App\Commands\GetFeedCommand("http://alerts.weather.gov/cap/us.atom")));
}
GetFeedController
use App\Commands\Command;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use GuzzleHttp\Client;
class GetFeedCommand extends Command implements ShouldBeQueued {
use InteractsWithQueue, SerializesModels;
public $guzzle;
public $uri;
/**
* Create a new command instance.
*
* #return void
*/
public function __construct($uri)
{
$this->guzzle = new Client;
$this->uri = $uri;
}
}
GetFeedControllerHelper
use App\Commands\GetFeedCommand;
use Illuminate\Queue\InteractsWithQueue;
class GetFeedCommandHandler {
/**
* Create the command handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the command.
*
* #param GetFeedCommand $command
* #return void
*/
public function handle(GetFeedCommand $command)
{
return $command->guzzle->get($command->uri)->xml();
}
}
Any help would be greatly appreciated! Thanks!
That is correct.
If you queue the command - then when you run it nothing will happen instantly, so it returns null. Meanwhile the command will run in the background on your queue processing system separately.
If you need an immediate reply - then just run the command without the queue.
Related
There are millions of records in a database table.
purchase
id (increments), device_id (int), app_id (int), status(boolean), receipt (string)
My framework laravel 8 and I use mysql
I have created a command
app/Console/Commands/ProcessPurchase.php
<?php
namespace App\Console\Commands;
use App\Models\Purchase;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Queue;
use App\Jobs\ProcessPurchaseJob;
class ProcessPurchase extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'process:purchase';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
Log::info('process:purchase command start successfully.');
$purchases = Purchase::getUnequalizedPurchases(250);
if(count($purchases) > 0) {
foreach ($purchases as $purchase) {
//push job to the queue
Queue::push((new ProcessPurchaseJob($purchase, $purchase->os)));
}
} else {
Log::info('process:purchase command end successfully.');
}
}
}
and created a job
app/Console/Commands/ProcessPurchaseJob.php
<?php
namespace App\Jobs;
use App\Models\Purchase;
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\Log;
class ProcessPurchaseJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $purchase, $os;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(Purchase $purchase, string $os)
{
$this->purchase = $purchase;
$this->os = $os;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//getting data from the third-party endpoint
if($purchaseData = getPurchaseDataFromMarket($this->purchase->receipt, $this->os)) {
$this->purchase->expire_date = $purchaseData['expire_date'];
$this->purchase->status = $purchaseData['status'];
try {
$this->purchase->save();
Log::info('purchase job runned successfully. receipt : ' . $this->purchase->receipt);
} catch (\Exception $exception) {
Log::error($exception->getMessage());
}
} else {
Log::error('purchase request error. receipt : ' . $this->purchase->receipt);
}
}
}
and added to app/http/Console/Kernel.php
$schedule->command('process:purchase')
->everyFiveMinutes();
to start cron, execute this command.
./vendor/bin/sail artisan schedule:work
to do the jobs in queue, execute this command
./vendor/bin/sail artisan queue:work --queue=high,default
I should send a request to third-party HTTP endpoint and update per every record.
This process take 1.5 secs about per a record. So, for 10.000.000 records, it takes 173.6 days.
I should can process all these data in a short time. (like 12 hours etc.)
What should i do ?
I have a markdown Birthday Notification email Template. I want to send a notification to user on their birthday using Cron job. The Cron job works perfectly but isn't working when I try to send email or add Email function to handle it.
This is my Code please
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Mail\BirthdaymessageMail;
use Illuminate\Support\Facades\Mail;
use App\Models\Employee;
class BirthdayCron extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'birthday:cron';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Notify Employee On Birthday';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$this->birthDayNotification();
}
private function birthDayNotification()
{
Mail::to('asamoa69#yahoo.com')->send(new BirthdaymessageMail());
}
}
Please what's the right way to do this? I need assistance. Thank you.
So consider the service provider, yes I know I am registering this command in two places, but just give me a moment to explain:
<?php
namespace App\Modules\Core\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Foundation\AliasLoader;
use App\Modules\Core\Handlers\RedirectHandler;
use App\Modules\Core\Console\Commands\CreateAdminUser;
use App\Modules\Core\Values\IsMedicalRecordEmpty;
class CoreProvider extends ServiceProvider
{
protected $commands = [
CreateAdminUser::class,
];
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(RedirectHandler::class, function($app) {
return new RedirectHandler();
});
$this->app->bind(IsMedicalRecordEmpty::class, function($app) {
return new IsMedicalRecordEmpty();
});
}
public function register() {
$this->commands($this->commands);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
CreateAdminUser::class,
]);
}
}
}
So as stated before we can see that I am registering this command in two places, because I am trying to figure out why calling php artisan doesn't show the command, it only shows if I register it in the app\Console\Kernel, but because I am trying to take a modular approach to the code base, I want to register it in my service provider, to which is registered as such:
'providers' => [
...
/**
* Module Related Providers
*/
App\Modules\Core\Providers\CoreProvider::class,
...
],
I register the provider properly, I (yes I know I don't need to register the command twice) register the command in the way that stack has explained it, either way should in theory work.
But alas the command does not show up when I run php artisan. At all.
The command is simple:
<?php
namespace App\Modules\Core\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use Illuminate\Auth\Events\Verified;
use App\Modules\Core\Users\Mail\GeneratedAdmin;
use App\Modules\Core\Users\Models\User;
use App\Modules\Core\Users\Services\RegisterUserService;
class CreateAdminUser extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'create:admin {first_name} {last_name} {email}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Create one admin.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
// do stuff here ...
}
}
Any ideas?
Your code is redeclaring register(), first in the method with the binds, and then again with your method calling $this->command() - are you even referencing your service provider correctly? PHP should have told you this - it did for me when I tried your sample code...
Whoops\Exception\ErrorException : Cannot redeclare App\Modules\Core\Providers\CoreProvider::register()
It's worth noting that removing the first method with the binds caused the command to show for me.
I currently have a live app that i am making huge changes too so i am working locally using Homestead. I previously used One Queue but with changes and all that i had to run multiple queues. The previous default queues was meant to make rows in a database table and one of the recent ones was to send emails. then i needed another one that I need to make rows in another table as well...issue is sometimes it works and other times it fails and sometimes it only creates one row before failing. the most annoying thing is that it is supposed to fire an event per row created in the database but that does not even occur at all. I had done it effectively before and it never failed me even the default queue still works fine.
here is the controller:
<?php
namespace App\Http\Controllers;
use Redirect;
use App\Short;
use App\Wallet;
use \SplFixedArray;
use App\Jobs\ShortQueuer;
use Illuminate\Http\Request;
use App\Http\Requests\SlotRequest;
class ShortController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('short_term_goals');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(SlotRequest $request)
{
$quota = 2;
$slotquota = request('slotamount') + $quota;
if ( auth()->user()->wallet->balance < $slotquota ) {
return Redirect::back()->with('low_balance', 'You do not have a sufficient wallet balance to reserve these SLOTS. Please Load Up Your Wallet');
} else {
// Getting SLOTS as objects of an array
$slotquantity = new SplFixedArray(request('slotamount'));
$slotquantity = $slotquantity->toArray();
$user = auth()->user();
ShortQueuer::dispatch($slotquantity, $user)->onQueue('shorts');
}
//Sorting Wallet Balance
$wallet = Wallet::where('user_id', auth()->user()->id)->first();
$wallet->balance = $wallet->balance - $slotquota;
$wallet->save();
//Returning View With Message
return Redirect::back()->with('reserved', 'Your Short Term Goals are Currently being met .');
}
/**
* Display the specified resource.
*
* #param \App\Short $short
* #return \Illuminate\Http\Response
*/
public function show(Short $short)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Short $short
* #return \Illuminate\Http\Response
*/
public function edit(Short $short)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Short $short
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Short $short)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param \App\Short $short
* #return \Illuminate\Http\Response
*/
public function destroy(Short $short)
{
//
}
}
Here is the job
<?php
namespace App\Jobs;
use App\Short;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class ShortQueuer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $slotquantity;
protected $user;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(array $slotquantity, $user)
{
$this->slotquantity = $slotquantity;
$this->user = $user;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// Inserting Rows in SLOTS Table
foreach ($this->slotquantity as $short) {
$short = new Short();
$short->user_id = $this->user->id;
$short->save();
//Slot Counting Event
event(new ShortCounter);
}
}
public $tries = 1;
public $timeout = 86400;
public $retryAfter = 87000;
}
here is the event
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ShortCounter
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
Here is the listener
<?php
namespace App\Listeners;
use App\Short;
use App\Goal;
use App\Events\ShortCounter;
use Illuminate\Http\Request;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class GoalCreator
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param ShortCounter $event
* #return void
*/
public function handle(ShortCounter $event)
{
$shortcount = Short::all()->count();
if($shortcount == 800) {
$goalshort = Short::latest()->first();
$goal = new Goal();
$goal->gid = unique_random('goals', 'sgid', 8);
$goal->grc = unique_random('goals', 'sgrc', 12);
$goal->status = 0;
$goal->amount = 200;
$goal->user_id = $goalshort->user_id;
$goal->save();
Short::truncate();
}
}
}
I sort it out.....I went through the error logs and solved the errors one after the other. First I forgot to include the Event Class in the Job, then a column name in my database was wrong then I restarted my server.
I have two models with many to many relationship artists and songs.
then there are fields in my artists table called weekhits and week_date,
i want to increment the value of week-hits when ever a specific artist page is visited by the user
so made event listners
class ArtistEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $artist;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(artist $artist)
{
//
$this->artist = $artist;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
ant this is the listener
class ArtistViewed
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param ArtistEvent $event
* #return void
*/
public function handle(ArtistEvent $event)
{
$event->artist->increment('week_hits');
}
}
and here is where i fired the listener.
public function artist($id,$slug){
$artist = Artist::where('id', $id)->where('slug', $slug)->first();
Event::fire(new ArtistViewed($artist));
return view('front.artist', compact('artist'));
}
but this code isnot incrementing week-hits field in my artists table..
plz help. iam in the middle of learning laravel.
I have already added an answer that suggests using a job for this, but if you want to go with the existing event/listener setup then just fix the call to Event::fire() to actually fire your event, not your listener.
Event::fire(new ArtistEvent($artist))
Also ensure that the event and listener are registered in your EventServiceProvider's $listen array.
\App\Events\ArtistEvent::class => [
\App\Listeners\ArtistViewed::class
]
I think you're confusing events and listeners - you're firing off the listener to Event::fire() and you pass the $artist into the constructor of the listener, but instead try and take it off the $event.
Keep in mind if your queue driver isn't sync then you will actually need to run your queue from the command line, otherwise these jobs will never be run.
Below is an example of how you might do this with a job that you dispatch. You could fire this off by calling dispatch(new RecordArtistView($artist)).
<?php
namespace App\Jobs;
use App\Artist;
use App\Jobs\Job;
use Illuminate\Contracts\Queue\ShouldQueue;
class RecordArtistView extends Job implements ShouldQueue
{
protected $artist;
/**
* Create a new job instance.
*
* #param \App\Artist $artist
* #return void
*/
public function __construct(Artist $artist)
{
$this->artist = $artist;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$this->artist->increment('week_hits');
}
}