Laravel 4.1 + Push Queues + Error Queues - laravel-4

My goal is to somehow notify me if a push message fails after X attempts.
Iron.io push queues docs describe: Error Queues
http://dev.iron.io/mq/reference/push_queues/#error_queues
Following the docs, I have to define an error_queue option in order to failed messages trigger a message in the specified error_queue option.
How can I define an option if push method in IronQueue.php doesn't support option argument. I see that pushRaw does support option argument.
How can I transform the following push example into a pushRaw
Route::get('someroute', function()
{
Queue::push('SomeClass', array('time' => time()));
});
class SomeClass{
public function fire($job, $data)
{
// do something
$job->delete();
}
}
Other ways of detecting push queues fails are also welcome.

As #cmancre said, you can use HUD to set the error queue or you could use the API to set it: http://dev.iron.io/mq/reference/api/#update_a_message_queue

Iron guys just rolled out an UI allowing us to set a error_error via iron admin panel.

In case your error_queue is already firing, to complete the cycle, you need to know which message failed.
To grab the error message information, in the error_queue route just do:
// First we fetch the Request instance
$request = Request::instance();
// Now we can get the content from it
$content = $request->getContent();
Reference: http://www.codingswag.com/2013/07/get-raw-post-data-in-laravel/

Related

How can I assert notification for a group of users?

I went through notification testing and have to check the notification routing but I have problem when it comes to group assertions. For a single receiver, all tests passes with the default Notification::assertSentTo method. But things were different when it goes to group notification. I have tried to swap between 3 approaches;
This approach gave a warning stating that This test did not perform any assertions
$author->company->employees()->role('hrd')->each(function ($hrd) {
Notification::assertSentTo($hrd, LeaveRequestNotification::class);
});
Same warning, but with foreach
foreach($author->company->employees->role('hrd') as $hrd) {
Notification::assertSentTo($hrd, LeaveRequestNotification::class);
}
BadMethodCallException with test going red.
Notification::assertSentTo(
$author->company->employees()->role('hrd'),
LeaveRequestNotification::class,
);
Here is the complete error message occured by the 3rd approach
$ test --testsuite=Unit --filter=LeaveTest::testShouldSendRequestNotificationToHrdsWhenAuthorIsRegularEmployee --stop-on-failure
FAIL Tests\Unit\LeaveTest
⨯ should send request notification to hrds when author is regular employee
---
• Tests\Unit\LeaveTest > should send request notification to hrds when author is regular employee
BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::getKey()
So, what is the proper way for doing this?
Just found the problem, it was lying here on the assignRole loop, I used the wrong subject
$leave->company->employees
instead of
$author->company->employees
The loop:
foreach ($leave->company->employees as $employee) {
if (!$employee->hasRole('employee')) {
$employee->assignRole('hrd');
}
}
dd($author->company->employees()->role('hrd')->count()); // prints 0
I changed the subject and use the 3rd approach, only this time, I add get() after the role definition. Works fine with no error. Thanks for #mrhn for reminding me about the existence of the loop subject.
foreach ($author->company->employees as $employee) {
if (!$employee->hasRole('employee')) {
$employee->assignRole('hrd');
}
}
LeaveRequest::dispatch($leave);
Notification::assertSentTo(
$author->company->employees()->role('hrd')->get(),
LeaveRequestNotification::class,
);

Laravel 5.6 one event and many optional listeners

in Laravel 5.6
I have an event named DocumentSend,
And i have many Listeners Like (SendEmail, SendNotification, SendSMS),
listeners are optional (depends on document type and defined by user),
now the question is:
How can i call for example DocumentSend event with just SendSMS listener or DocumentSend with all the listeners?
I hope you get my mean,and tell me the best practice for my issue.
Thanks in advance
Well, the simple answers is - you can't. When you fire event all registered listeners will listen to this event and all of them will be launched.
However nothing stops you to prevent running code from listener.
For example you can fire event like this:
event(new DocumentSend($document, true, false, false));
and define constructor of DocumentSend like this:
public function __construct($document, $sendEmail, $sendNotification, $sendSms)
{
$this->document = $document;
$this->sendEmail = $sendEmail;
$this->sendNotification = $sendNotification;
$this->sendSms = $sendSms;
}
and now in each listener you can just verify correct variable, so for example in SendEmail listener in handle you can do it like this:
public function handle(DocumentSend $event)
{
if (!$event->sendSms) {
return;
}
// here your code for sending
}
similar you can do for other listeners.
Of course this is just example - you don't have to use 4 variables. You can set some properties to $document only to mark how it should be sent.

Laravel Cashier - Stripe webhook handling

I am handling a webhook for failed payments and the webhook is being successfully called. However, from the Laravel documentation it appears that a subscription would be automatically cancelled after 3 failed payments. In my case it is not being cancelled.
Is it because I have overridden the inbuilt behaviour? Or have I missed a trick?
Here is my webhook code:
public function handleChargeFailed(array $payload)
{
//first log the event in full
Log::info('Charge Failed - StripeWebhook - handleChargeFailed()', ['details' => json_encode($payload)]);
$tenant = Tenant::where('stripe_id', $payload['data']['object']['customer'])->first();
Mail::send(
//...//
});
return new Response('Webhook Handled', 200);
}
I have solved it myself - in case anyone else has the same issue. Once you handle a webhook yourself you need to completely handle it. In other words you have overridden completely the default inbuilt handling.

Database notifications don't show up after testing notify

I have a unit test with the following:
use \Illuminate\Notifications\DatabaseNotification;
public function testMailSentAndLogged()
{
Notification::fake();
$user = factory(User::class)->create();
$emailAddress = $user->emailAddress;
$emailAddress->notify(new UserCreated);
Notification::assertSentTo(
$emailAddress,
UserCreated::class
);
error_log('DatabaseNotification '.print_r(DatabaseNotification::get()->toArray(), 1));
$this->assertEquals(1, $emailAddress->notifications->count());
}
My Notification has this for the via():
public final function via($notifiable)
{
// complex logic...
error_log('mail, database');
return ['mail', 'database'];
}
The code fails on the $this->assertEquals code. the error_log produces the following:
[03-Jan-2018 01:23:01 UTC] mail, database
[03-Jan-2018 01:23:01 UTC] DatabaseNotification Array
(
)
WHY don't the $emailAddress->notifications pull up anything? Why doesn't DatabaseNotification::get() pull anything?;
In your test, you are calling the method
Notification::fake();
As stated in Laravel's documentation on Mocking,
You may use the Notification facade's fake method to prevent
notifications from being sent.
Actually, this bit of code is the assertion that the Notification would have been sent, under normal circumstances (ie in prod) :
Notification::assertSentTo();
If you remove the call to Notification::fake(), your notification should appear in your testing database.
So you kinda have two solutions. The first one is to remove the call to fake(), thus really sending the notification, which will appear in the database. the second is not to test if the notification was written successfully in the database : it's Laravel's responsibility, not your application's. I recommand the second solution :)

HOW TO: Get real-time notifications in Laravel 4 using Iron.io MQ, Push Queues & AJAX

I've integrated ironMQ push queues in my Laravel 4 app for longer running processes. I have some views that perform a $.get that might take 30 seconds. I wanted to see what others are doing to easily get notified when ironMQ is done pushing back to an endpoint.
An example of what I will be doing with push queues mostly:
public function getCompletedTasks() {
$user = User::find(Auth::user()->id);
Queue::push(function($job) use ($user) {
$recent = new Recent;
$tasks = $recent->getCompletedTasks($user);
// append data from $tasks to DOM
// here's where I want to receive my notification
});
}
Here I am just getting tasks from an API that match data from user.
I know I can store the response data to a database and use AJAX long polling to constantly check for the data but it seems like too much work for most situations I will need to do this. I don't know much about websockets. What types of things have you guys done in these situations? And if you have any examples that would be very helpful. Thanks.
UPDATE: Solved the issue using Pusher. See my answer.
I was able to solve my problem with the help of Pusher. Here's what I did:
Setup my Iron MQ push queue as normal. In routes.php:
Route::post('queue/push', function() {
return Queue::marshal();
});
Installed pusher laravel package.
In my controller then I Queue::push my data. Inside the closure I trigger a new Pusher channel. This will obviously only trigger when the data has been returned from IronMQ.
public function getCompletedTasks() {
$user = User::find(Auth::user()->id);
Queue::push(function($job) use ($user) {
$recent = new Recent;
$tasks = $recent->getCompletedTasks($user);
$pusher = new Pusher('xxx', 'xxx', 'xxx');
$pusher->trigger('reports', 'get_completed_tasks', array('tasks' => $tasks));
$job->delete();
});
});
Next in my view I call my AJAX function with no callback since I won't be doing anything else just yet:
$.get('account/tasks/completed');
Next in my view I initialize Pusher, subscribe to the event and bind get_completed_tasks to the Pusher channel. Now we just wait for a response from Pusher which will then allow me to perform the latter part of my original AJAX request:
{{ HTML::script('//js.pusher.com/2.1/pusher.min.js') }}
<script>
var pusher = new Pusher('xxx');
var channel = pusher.subscribe('reports');
channel.bind('get_completed_tasks', function(data) {
// do something with the data returned
});
</script>
Once I used Pusher in my app, the rest was a breeze. Hope this helps someone!

Resources