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.
Related
I'm trying to send email notifications to my app users, limiting the number of emails to only 2 per minute, so as not to breach my email provider's allowed sending rate. So in MailingController.php I have:
<?php
namespace App\Http\Controllers;
use App\Jobs\SendMessages;
use Illuminate\Http\Request;
class MailingController extends Controller
{
public function send(Request $request) {
SendMessages::dispatch();
return redirect()->back()->withSuccess('Successful operation.');
}
}
SendMessages.php content is:
<?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\Jobs\Middleware\RateLimited;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Redis;
class SendMessages implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 7200;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$users = User::all();
foreach ($users as $user) {
Log::debug('SendMessages#handle() ' . $user->email);
$user->notify(new VerifyEmail);
}
}
public function middleware()
{
return [new RateLimited];
}
}
And finally, RateLimited.php content is:
<?php
namespace App\Jobs\Middleware;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
class RateLimited
{
/**
* Process the queued job.
*
* #param mixed $job
* #param callable $next
* #return mixed
*/
public function handle($job, $next)
{
Redis::throttle('key')
->block(0)->allow(1)->every(30)
->then(function () use ($job, $next) {
// Lock obtained...
Log::debug('RateLimited');
$next($job);
}, function () use ($job) {
// Could not obtain lock...
$job->release(16);
});
}
}
All these are copied and pasted from a Laravel 8 application that works perfectly fine, sending one email every 30 seconds as expected, but in my brand new Laravel 9 application the same code no longer works, and all email notifications are sent at once. I know I must be missing something, but have ran out of ideas. Any help would be greatly appreciated.
Thank you.
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 try to send notification via pusher when user submitted new order.
in my CartController where I save data into my orders table I have:
<?php
use App\Events\UserOrdered;
//codes....
public function checkout(Request $request) {
//rest of the code
Auth::user()->orders()->save($order);
event(new UserOrdered($order));
//Cart::clear();
Session::flash('success', 'Thank you. Your order has been received.');
return redirect()->route('ordersindex');
}
when I hit to save my order i will get 404 NOT FOUND on event(new UserOrdered($order));
Here is my Event code:
<?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;
use App\Order;
class UserOrdered implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $order;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('order-placed');
}
}
This is my Listener code:
<?php
namespace App\Listeners;
use App\Events\UserOrdered;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendNotification
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param UserOrdered $event
* #return void
*/
public function handle(UserOrdered $event)
{
$pusher->trigger($event, 'order-placed', $order);
}
}
PS: When I try my pusher from pusher website Debug Console i can get notification. Whatever problem is, is from event and listener.
Any idea?
UPDATE
update 2
I managed to get pusher to work (i know is not the best way but it works at least).
here is my listener now:
<?php
namespace App\Listeners;
use App\Events\UserOrdered;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Pusher\Pusher;
use Mail;
class SendNotification
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param UserOrdered $event
* #return void
*/
public function handle(UserOrdered $event)
{
Mail::to($event->order->buyer_email)->send(new UserOrdered($event->order));
$options = array(
'cluster' => 'ap1',
'encrypted' => true
);
$pusher = new Pusher(
'xxxxx', //id
'xxxxx', //key
'xxxx', //secret_key
$options
);
$pusher->trigger('UserOrdered', 'order-placed', $event->order);
}
}
What I need?
Pusher will show notification in admin as new order placed. done
I also want to send 2 emails one to admin to say he/she has new
order, and another to user to say that we received his/her order.
mail function:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Order;
class UserOrdered extends Mailable
{
use Queueable, SerializesModels;
public $order;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from('noreply#tester.com')->subject('Your Order recieved!')->markdown('emails.orders');
}
}
Progress: In order to send emails I added Mail::to in my listener as you see above, and added code below to my controller function:
//rest of the code...
Auth::user()->orders()->save($order);
$user = $order->buyer_email;
event(new UserOrdered($order));
Mail::to($request->user)->send(new UserOrdered($order)); //added newly
//Cart::clear();
Session::flash('success', 'Thank you. Your order has been received.');
return redirect()->route('ordersindex');
Problem is:
I get this error
Type error: Argument 1 passed to Illuminate\Mail\PendingMail::send()
must be an instance of Illuminate\Mail\Mailable, instance of
App\Events\UserOrdered given
refers to: Mail::to($event->order->buyer_email)->send(new UserOrdered($event->order));
if I change $event->order at the end of that to something static like $event I will get:
Type error: Argument 1 passed to App\Events\UserOrdered::__construct()
must be an instance of App\Order, instance of App\Events\UserOrdered
given
any idea?
I'm trying to create job to register users and tried to follow Jeffrey's video but looks like dispatchfrom is removed for some reason. This is what i'm trying to do now:
This is my controller:
public function PostSignUp(Request $request)
{
dispatch(new RegisterUser($request->all()));
return 'done';
}
This is my job:
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class RegisterUser implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
protected $request;
/**
* Create a new job instance.
* #param $request
* #return void
*/
public function __construct($request)
{
$this->request = $request;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = $this->request->email;
var_dump('I should register user with email:' . $email);
}
}
I also tried to put
just $request instead of $request->all()
but then i get
Serialization of 'Closure' is not allowed
And now I'm getting Trying to get property of non-object error. Is this good way to pass whole request to job ? Should i do it some other way ?
try with input()
$request->input()
When you do $request->all(), that means you are passing an array to the job and not the whole $request. Therefore, you can simply do this in your Job Handler.
public function handle()
{
$email = $this->request['email'];
var_dump('I should register user with email:' . $email);
}
Let me know if something else is required :)
I'm using the thujohn/twitter package on https://github.com/thujohn/twitter to update user status posts from my site to twitter.
I want to use larvae's queues to post this function in the background. But i keep getting a failed-job. with an error:
exception 'Exception' with message '[220] Your credentials do not allow access to this resource.' in /home/vagrant/sites/pms/vendor/thujohn/twitter/src/Thujohn/Twitter/Twitter.php:297
Stack trace:
my job looks like this:
namespace PMS\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Twitter;
use Session;
use Illuminate\Http\Request;
class PostToTwitter implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
public $tweetLength;
public $userPage;
public $body;
//public $twitterToken;
//public $secret;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($tweetLength, $userPage, $body)
{
$this->tweetLength = $tweetLength;
$this->userpage = $userPage;
$this->body = $body;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Twitter::postTweet(['status' => str_limit($this->body . $this->userpage,$this->tweetLength), 'format' => 'json']);
}
}
and in my controller I'm dispatching like this:
$this->dispatch(new PostToTwitter($tweetLength, $userPage, $body));
my function works fine if i run it in my controller , but if i try to dispatch it to a job, my jobs fail
I managed to fix this by switching to a different library, following this blog post: http://markusos.github.io/engage/2014/12/06/1000-tweets-per-week.html