How to run MQTT subscribe in the background in Laravel - laravel

I am trying to put MQTT subscribe into a job saved in the database, but I get an error message that the job has failed instead of running for an infinite time. I would like to know if my approach is even possible and if there are any better alternatives to my problem.
My code
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 PhpMqtt\Client\Facades\MQTT;
class StartSub implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct()
{
//
}
public function handle()
{
$mqtt = MQTT::connection();
$mqtt->subscribe('topic', function (string $topic, string $message) {
echo sprintf('Received QoS level 1 message on topic [%s]: %s',
$topic, $message);
}, 1);
$mqtt->loop(true);
}
}

The answer is pretty simple. Although I do not know if it is 100% correct. After further investigation I found out that my code was failing because of time out. So i just had to put a public $timeout = 0;.

Related

Undefined eager-loaded relationship when using Echo event broadcasting

I am using Laravel Echo in my project to broadcast events to the client-side. Everything is working correctly, however, I am having a problem in eager-loading the relationships of the model for the Event.
My Controller
$chat = new Chat;
$chat->user_id = $request->user_id;
$chat->message = $request->message;
$chat->save();
event( new GetMessages( $chat ));
My Event class:
class GetMessages implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $chats;
public function __construct($chats)
{
$this->chats = $chats;
}
public function broadcastOn()
{
return ['get-messages'];
}
public function broadcastAs()
{
return 'get-messages';
}
}
Here is my Laravel Echo
Echo.channel('get-messages')
.listen('.get-messages', (data) => {
console.log(data)
})
Everything is working fine as I expected, except getting the attachments from the Chat.
console.log(data.chats); // Undefined
Is there something I missed? Because as I tested the eager-loaded from the Event class itself, I can access the attachments in there.
public $chats;
public function __construct($chats)
{
$this->chats = $chats;
echo $chats->attachments // It's working in here, I can get the attachments
}
Hope I explain it well, Thank you in advance
Cheers!
Here is the console.log
Here is use, it's the default when I created the Event
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 GetMessages implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
...

Laravel dispatch queue always intermediately run

I am trying to dispatch jobs in Laravel into mysql. If I do
dispatch(new SendBroadcastSMS());
or
SendBroadcastSMS::dispatch()->delay(now()->addMinutes(2));
The job always runs intermediately. In my job, I set to sleep 30 seconds and my current controller/page that calls dispatch also waiting for 30 seconds and echo the job return. Why? It should run in the background via worker right? Or I misunderstand with the laravel queue?
My job is like below:
<?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;
class SendBroadcastSMS implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct()
{
}
public function handle()
{
sleep(30);
echo "test";
// dd($this->sendSms("6281517777767","test message"));
//
}
}
my queue driver is database mysql and I also not receieved any row in job table
QUEUE_DRIVER=database
QUEUE_DRIVER is not the property you should set in your .env file.
The correct property is QUEUE_CONNECTION.
QUEUE_CONNECTION=database

how to broadcast event called by job class

In a Laravel project i am trying to broadcast a event named "closed" via pusher.
In my controller i am calling:
App\Jobs\Closing::dispatch();
My App\Jobs\Closing.php:
<?php
namespace App\Jobs;
use App\Jobs\Close;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class Closing implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(){}
public function handle()
{
$delay = mt_random(10,20);
Close::dispatch()->delay(now()->addSeconds($delay));
}
}
My app\Jobs\Close.php:
<?php
namespace App\Jobs;
use App\Events\Closed;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class Close implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(){}
public function handle()
{
event(new Closed());
}
}
My App\Events\Closed.php:
<?php
namespace App\Events;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class Closed implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(){}
public function broadcastOn()
{
return ['updates'];
}
public function broadcastAs()
{
return 'closed';
}
public function broadcastWith()
{
return ['message' => 'Is Closed!'];
}
}
At this point i need to explain two mandatory situations.
The first one is that i needed to create the job Close class as a job because i needed to delay the execution of the task close. And the only way i can see to make this "delay" is with a Job Class.
The second one is that i have chosen to implement "ShouldBroadcastNow" instead of "ShouldBroadcast" in the event Closed class because i don't want to queue the broadcasting.
Now the problem is that after running:
php artisan queue:work --tries=1
i get in the following output on Command Console:
Processing: App\Jobs\Closing
Processed: App\Jobs\Closing
Processing: App\Jobs\Close
Processing: App\Events\Closed
Failed: App\Events\Closed
Failed: App\Jobs\Close
The first thing that i find weird is that App\Events\Closed goes to queue despite the fact that it implements "ShouldBroadcastNow".
On laravel.log it seems that it occurred a BroadcastException at PusherBroadcaster.php.
But if in the Controller i do:
event(new App\Events\Closed());
the event is properly broadcast via pusher to the client browser.
What is going wrong?
Is there other way do delay the "close" without jobs?
The purpose is to have the following workflow:
1 - We have a event named "closing" an another event named "closed";
2 - We have a task named "close" that occurs "x" seconds after the event "closing", where "x" is a random number;
3 - After the execution of "close" task we broadcast the event "closed".
Thank you for your attention to my problem
Meanwhile i found this is a already known issue (https://github.com/laravel/framework/issues/16478).
It can be solved in two ways:
1 - editing the relevants php.ini files (in my case it was mamp/conf/php7.0.9/php.ini and mamp/bin/php/php7.0.9/php.ini) to point at the location of curl certificate;
2 - editing config/broadcasting.php (setting encrypted to false in pusher options).

Laravel mail Invalid view

I have a command in my code that is run daily by cron that sends emails to all new users. It used to work ok, but after I have swithched the queue driver to SQS and upgraded Laravel 5.2 to 5.3 it started throwing an error.
InvalidArgumentExceptionvendor/laravel/framework/src/Illuminate/Mail/Mailer.php:379
Invalid view.
I don't know what might cause the error, because I have not deleted the view. Also when I run the command manually it does not throw any errors.
Here is the command code:
public function handle()
{
$subscriptions = Purchase::where('created_at', '>=', Carbon::now()->subDay())
->groupBy('user_id')
->get();
$bar = $this->output->createProgressBar(count($subscriptions));
foreach ($subscriptions as $subscription) {
$user = $subscription->user;
// if ($user->is_active_customer) {
Mail::to($user)->bcc(env('BCC_RECEIPTS_EMAIL'))->send(new NeedHelp());
// }
$bar->advance();
}
$bar->finish();
$this->info("\nSuccess! " . number_format(count($subscriptions)) . ' emails were sent.');
}
Here is the NeedHelp class code (I have changed the email and sender name for this thread):
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NeedHelp extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
*/
public function __construct(){
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Need help?')
->from('default#mail.com', 'Sender')
->view('emails.need-help');
}
}
I have found the error. The reason was that I have accidentally connected two applications to the same queue, which caused them to process jobs and emails of each other which resulted in this error.

Have a queue job always running

I have a queue job that I need to have constantly running.
That means that when the job is finished processing, it should start the job all over again.
How can I do this?
Here's my job:
<?php
namespace App\Jobs;
use App\User;
use App\Post;
use App\Jobs\Job;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class PostJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function handle()
{
$posts = Post::where('user_id', $this->user->id)
->get();
foreach ($posts as $post) {
// perform actions
}
}
}
Here's the job controller:
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use App\Jobs\SendReminderEmail;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
public function startPostJob(Request $request, $id)
{
$users = User::all();
foreach ($users as $user) {
$this->dispatch(new PostJob($user));
}
}
}
The queue is meant for one time request, not continuous job running. Your architecture should probably move to more of a cron job setup so you can set intervals to re-run your desired code.
Have a look at the task scheduling documentation here https://laravel.com/docs/5.1/scheduling
The forever running Job, does not sound like the best idea, mostly because it could easily lead to a lot of cpu power being used. But i have done job chaining, which i achieved a certain way, and i think this can help you to solve your problem.
What i usually do, is make the responsibility of a Model specific job, the models responsibility. This will make it easier to invoke from the job.
public class User{
use DispatchesJobs; //must use, for dispatching jobs
...
public function startJob()
{
$this->dispatch(new PostJob($this));
}
}
This will give you the possibility of chaining the jobs together, after the job has ended. Remember to delete the job, after it has finished. And will continue for ever, by creating a new job each time.
public function handle()
{
...
foreach ($posts as $post) {
// perform actions
}
$this->user->startJob();
$this->delete();
}

Resources