How to notify the user that a job has completed in Laravel? - php

in Laravel, you can use jobs to execute tasks in a back-end queue while the rest of the application does other things. i have a job that is initiated by user input. immediately, through javascript, i give the user a notification that the job is being processed.
i would like to be able to give a similar notification after the job has successfully completed.
i am calling my job from within a model like this:
public function doSomething() {
$job = new \App\Jobs\MyJob();
app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
}
and this is how my job headers look like:
class MyJob extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue, SerializesModels, Queueable;
...
}
the model job call is actually triggered from a controller method:
public function getDoSomething($id) {
$item = Item::findOrFail($id);
$item->doSomething();
return response()->json(true);
}
which is handled by an AJAX call:
$.ajax({
url: $(this).attr('href'),
type: 'GET',
dataType: 'json',
success: $.proxy(function(result) {
this.application.notification.showMessage('Job is being processed.');
}, this),
error: $.proxy(function(result) {
console.error(result);
}, this)
});

You can user Queue::after function on your AppServiceProvider
Import this dependencies
use Illuminate\Support\Facades\Queue;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
And on boot method you would use it
public function boot()
{
Queue::before(function (JobProcessing $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
Queue::after(function (JobProcessed $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
}

Probably I'm late for the party guys, but there are several options i can think of. When user clicks button from the front-end you can give attribute disabled to it and some text like 'processing'. Then you can:
Just ping your endpoint to check if what job is performing is finished
Use websockets
I think Forge is doing websockets using pusher the endpoint to see if server is active when you are trying to deploy new code. I can clearly see the communication if you open Devtools->Resources->Sockets.

You can use queue events, Laravel document explains it: https://laravel.com/docs/5.6/queues#job-events

Job Completion Event
The Queue::after method allows you to register a callback to be executed when a queued job executes successfully. This callback is a great opportunity to perform additional logging, queue a subsequent job, or increment statistics for a dashboard.
This already in the page link you shared from Laravel.

Related

laravel-notification-channels/apn either isn't sending notification or my iPhone isn't receiving the notification

I am using this package to try and send apn notifications in my Laravel app. However, I have followed the documentation on the main page, and when I try to send an apn notification, I can log on the server that the constructor and via methods are called, but I can't figure out why my notification either isn't being sent or isn't being received. My logs have no info from the package either.
How do I troubleshoot this? What am I missing?
MyNotification.php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\Apn\ApnChannel;
use NotificationChannels\Apn\ApnMessage;
class MyNotification extends Notification
{
use Queueable;
public function __construct()
{
Log::debug('MyNotification constructor called');
}
public function via($notifiable)
{
Log::debug('MyNotification via called');
return [ApnChannel::class];
}
public function toApn($notifiable)
{
Log::debug('MyNotification toApn called');
return ApnMessage::create()
->badge(1)
->title('My title')
->body('My body');
}
public function routeNotificationForApn($notifiable)
{
Log::debug('MyNotification routeNotificationForApn called');
return $notifiable->token;
}
}
usage code in MyController.php
public function sendNotification(MyModel $model)
{
// authorization checks here...
$devices = Device::where('user_id', $model->user_id)->get();
Notification::send($devices, new MyNotification());
return response()->json(null, 200);
}
Here is what my broadcasting.php and .env files look like:
Your notification uses Queueable so your notifications are only send if your queue is correctly setup.
You can run your queue locally by running
$ php artisan queue:work
On your console you would also get a feedback if your queued job (your notification) has been submitted successfully (not if it is delivered successfully).
This is also highlighted inside the Laravel docs
Before queueing notifications you should configure your queue and start a worker.
If you need a queue that is probably sth. you need to decide as only you know how much load is the application, how many notifications should be sent.
Taken from the docs:
Sending notifications can take time, especially if the channel needs to make an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the ShouldQueue interface and Queueable trait to your class.
Personal opinion: Make it work without a queue, f. ex. locally, and then add a queue.
If you configured to run your queue with Redis, I would highly recommend to use Laravel Horizon to monitor the jobs in your queue.
Tips for using APN
Configure the APN service correctly in config/broadcasting.php - see Github docs.
The problem was that the function routeNotificationForApn() belongs in the notifiable model (in my instance, Device), not in the MyNotification class.
Removing the use Queueable; is required as well if you don't have a queue set up.

Laravel 5.6 Job Event Queue::after not firing after queue processed

In an application I am working, I've both Job and Event Listener implemented Should Queue. In the queue, I perform a database insert and I want after the queue complete, I want to remove the previous cache. So I use Queue Job Event like this example:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Queue::after(function (JobProcessed $event) {
Log::info('[QUEUE COMPLETE]', $event->job->getName());
});
}
public function register()
{
//
}
}
But the event is never fired and there is no log found in storage/log folder. I use daily logging channel.
Why is it not logging?
Answering my own question after solving this.
All the code is fine, I just needed to stop the queue:work and start it again (restart). After this, the Queue::after event started to fire and all worked perfectly.

Laravel / PHP - Run 3 php functions in parallel

I have 3 functions that get json data from external apis and then saves in my database. Each function is its in own class e.g :
Class api1 {
public function fetch()
{
//Do Something
}
}
Class api2 {
public function fetch()
{
//Do Something
}
}
Since its api call might take some time or delay . I want to run all 3 in parallel so that api2 does not have to wait for api1 to complete.
Any way to do that ?
* Note : I'm also going to use laravel scheduler which will run each function every minute or run a single function containing all 3.
To me this looks more of like callback request for data, so to keep your app from not slowing down this should be a background job.
But before that I would implement an interface for those classes:
interface apiService{
public function fetch();
}
Class api1 implements apiService {
public function fetch()
{
//Do Something
}
}
Class api2 implements apiService{
public function fetch()
{
//Do Something
}
}
Create a job class php artisan make:job dataFetcher
Jobs will be structured under App\Jobs\
The job class in Laravel its dead simple, consisting of a constructor to Inject dependencies and handle() to fire the job.
protected $service;
public function __construct(apiService $service)
{
$this->service = $service;
}
public function handle()
{
$this->apiService->fetch();
}
Note that I am injecting the interface instead of concrete class, using a bit more high level code here. So now you can create a command to fire the calls with a cron job, or you can create a custom service provider to fire the commands as soon as app bootstraps.
I would go with a custom artisan command here:
So just create a custom artisan command on handle method
public function handle()
{
Job::dispatch(new FirstApiClass);
Job::dispatch(new SecondApiClass);
}
Handle method will execute first line and Job will be processed in background(doesnt matter if job failed or not), then next call will be fired and so on...
Note the use of the interface in this case, Job class doesnt really care which service you are calling as long as you provide an implmenetation of it.

how to execute events asynchronously in laravel

Pls I'm still new to laravel and I have used events in laravel a couple of times but I'm curious and would like to know if it's possible to execute an event in laravel asynchronously. Like for instance in the code below:
<?php
namespace mazee\Http\Controllers;
class maincontroller extends Controller
{
public function index(){
Event::fire(new newaccountcreated($user)) ;
//do something
}
Is it possible for the block of code in the event listener of the "newaccountcreated" event to be executed asynchronously after the event is fired ?
Yes of course this is possible. You should read about Laravel Queues. Every driver (only not sync driver) are async. The easiest to configure is the database driver, but you can also want to try RabbitMQ server , here is Laravel bundle for it.
You can also add to your EventListener: newaccountcreated trait Illuminate\Queue\InteractsWithQueue (you can read about him here) which will helps you to connect it with Laravel Queue.
Filip's answer covers it all. I will add a bit more to it. If you push an event it will goto the default queue. You can specify a queue name as well. Have the listener class implements ShouldQueue and just include the queue method in the listener class like below.
/**
* Push a new job onto the queue.
**/
public function queue($queue, $job, $data)
{
return $queue->pushOn('queue-name', $job, $data);
}

Phalcon fire event from controller

I am using the Phalcon micro application as my REST web service. I want to add an event to the application and fire this event from different places like controllers.
For example; if a user registers, the controller should fire a userRegistered event, and userRegistered should do some stuff.
How can I implement this?
interface IUsers
{
function onUserRegistered();
}
Event class
class UsersActivities implements IUsers
{
function onUserRegistered()
{
// TODO: Implement onUserRegistered() method.
}
}
Just check docs. It's pretty simple, create manager, creat listener(UsersActivities in your case i guess) and fire events in manager.
https://docs.phalconphp.com/pl/latest/reference/events.html

Categories