Laravel job executing real time without queue being started - laravel

Running on Laravel 5.8
I am creating a large number of Jobs which I believe should be executed once the queue has been initiated.
My issue is that the jobs get executed then and there when I haven't even started the queue.
They are not even being inserted in to the jobs table created by the migration.
Below are the settings and the piece of code I believe is relevant. Please let me know if more info is needed.
On a fresh installation:
php artisan queue:table
php artisan migrate
.env file
QUEUE_CONNECTION=database
Created the queuedtask
class FulfillmentTask implements ShouldQueue{
//code here
}
Controller
use App\Jobs\FulfillmentTask;
//rest of the class here
public function somefunction(Request $request){
//some code here
//read csv file
foreach ($fileContents as $row){
FulfillmentTask::dispatch($orderId, $client, $request->sendEmail)->onQueue('database');
}
}
Issue is the FulfillmentTask is executed without the queue:work command being given in the terminal.
Any idea on why this is happening?

"database" is a queue connection. Pls dispatch your job to that connection.
FulfillmentTask::dispatch($orderId, $client, $request->sendEmail)->onConnection('database');
And that seems to be the default connection so you just dispatch the job.
FulfillmentTask::dispatch($orderId, $client, $request->sendEmail);

Related

Define database connection for supervisor

In my laravel 8 app, I have three database connections, viz Database-0, Database-1, Database-2.
Database-0 used for authenticating users so it has users table and Laravel Auth method retrieve user using this connection as I have set it in passport configuration file.
Database-1 and Database-2 connection used for all other purposes except authentication.
In my users table I have just two users with email first_user#example.com and second_user#example.com
When user is logged in with first_user#example.com then Database-1 should be used and if user is logged in with second_user#example.com then Database-2 should be used.
To acheive this I have created a middleware and register it in $middleware group so it run for all the request. In this middleware, I am checking the logged in user email and based on that I am setting database connection.
Up until now everything works perfectly
Now I have a job of that is being queued and I am using database as my QUEUE_CONNECTION. so my job stored in database jobs table. I have configured supervisor for processing this job.
Now the problem is when supervisor make query to retrieve job, my middleware doesn't get called and it throws following error
invalid catalog name: 1046 No database selected (SQL: select * from jobs where ....)
So my question is how can I set database connection for supervisor to choose from database when retrieving jobs?
middleware
public function handle(Request $request, Closure $next)
{
$auth_email = Auth::guard('api')->user()?->email;
if ($auth_email === 'first_user#example.com') {
config(['database.connections.fe_mysql.database' => 'Database-1']);
} elseif ($auth_email === 'second_user#example.com') {
config(['database.connections.fe_mysql.database' => 'Database-2']);
}
return $next($request);
}
supervisor config
[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/laravel-project/artisan queue:work --queue=admin
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stopwaitsecs=7200
stdout_logfile=/var/www/html/laravel-project/worker.log
Use the config() function to set extra or overwrite existing connection settings.
config(['database.connections.mynewconnection' => {settings here}]);
Keep in mind that these settings are cached. So when you need to use the new settings, purge the DB cache for the connection you're gonna use.
DB::purge('mynewconnection');
You can also manipulate the default connection that is used. This can come in handy if you wish to use migrations over different connections and keep track of them with a migration table within the used connection. Or other cool stuff ofcourse...
DB::setDefaultConnection('mynewconnection');

Laravel Jobs are not processed when triggered by a Redis subscribed message

I've some mistake with a job that I try to dispatch when my Redis subscribe command receive a message.
I launch the Redis subscribe inside an "artisan console" command :
Redis::subscribe(['channel'], function ($message) {
dipatch((new MyJob($message)
->onQueue('default')
->onConnection('redis'));
}
Job is created and I can see it on my Laravel Horizon dashboard. But it's never processed... "handle" function is never called and the job stay in "pending" tab on Horizon.
But when I dispatch it from a tinker session, that's work fine!
Maybe I have to call another artisan command to launch the job outside the redis subscribe function, but hope there is a better solution...
Any ideas?
Solution :
create another connection on the database.php file for your Redis database (same params as the default one, just change the name, eg name it "subscribe"), so after that change, the code must look like this :
$redis = Redis::connection('subscribe');
$redis->subscribe(['channel'], function () {});
I had the same problem, The job will never be dispatched on Redis queue. When I used another queue driver (database or beanstalkd) it worked fine.

What is the right way to send bulk mail with Laravel via AWS SES?

I've SES approved sending rate of 500 emails / second. When I try to send bulk email via Laravel using SES API, the actual mail sending rate is very slow (about ~100 per minute).
Here's an overview of how I do it -
...
Users::latest()->chunk(100, function($users) use($newsletter) {
Notification::send($users, new SendNewsLetter($newsletter)); // queued
})
My guess was that I'd send about 100 mails in one shot, however, Horizon shows that the queue which I'm using will have long wait time (of several seconds).
Can someone inform me what is the right way to send bulk emails using SES and Laravel?
First, i recommand you change the .env file setting for QUEUE_DRIVER=sync to QUEUE_DRIVER=database.
sending Email action
$users = Users::latest()->take(100)->get();
Mail::queue('send', ['users' => $users], function($m) use ($users) {
foreach ($users as $user) {
$m->to($user->email)->subject('YOUR SUBJECT GOES HERE');
}
});
As next step you need to create a Queue table in the database using
the following command before clicking on the route:
PHP artisan queue: table
PHP artisan migrate
Before starting the project you need to run a listener to listen to
the Queue Request. But you're gonna introduce with the new method as
listen is high CPU usage. It's better to use a daemon. So Run the
following command:
PHP artisan queue:work --daemon --tries=3
Source

Laravel app deployment in Heroku fails with handling the post-autoload-dump event returned with error code 1 [duplicate]

I have been using Eloquent as a standalone package in Slim Framework 2 successfully.
But now that I want to make use of Illuminate\Support\Facades\DB since I need to show some statistics by getting the info from 2 tables and using a Left Join and a Counter from the database like this:
use Illuminate\Support\Facades\DB;
$projectsbyarea = DB::table('projects AS p')
->select(DB::raw('DISTINCT a.area, COUNT(a.area) AS Quantity'))
->leftJoin('areas AS a','p.area_id','=','a.id')
->where('p.status','in_process')
->where('a.area','<>','NULL')
->orderBy('p.area_id');
I get the following error:
Type: RuntimeException
Message: A facade root has not been set.
File: ...\vendor\illuminate\support\Facades\Facade.php
Line: 206
How can I solve it?
So far I have found out, in this link that I need to create a new app container and then bind it to the Facade. But I haven't found out how to make it work.
This is how I started the rest of my Eloquent and working fine:
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule();
$capsule->addConnection([
'my' => $app->config->get('settings'),
/* more settings ...*/
]);
/*booting Eloquent*/
$capsule->bootEloquent();
How do I fix this?
Fixed
As #user5972059 said, I had to add $capsule->setAsGlobal();//This is important to make work the DB (Capsule) just above $capsule->bootEloquent();
Then, the query is executed like this:
use Illuminate\Database\Capsule\Manager as Capsule;
$projectsbyarea = Capsule::table('projects AS p')
->select(DB::raw('DISTINCT a.area, COUNT(a.area) AS Quantity'))
->leftJoin('areas AS a','p.area_id','=','a.id')
->where('p.status','in_process')
->where('a.area','<>','NULL')
->orderBy('p.area_id')
->get();
You have to change your code to:
$Capsule = new Capsule;
$Capsule->addConnection(config::get('database'));
$Capsule->setAsGlobal(); //this is important
$Capsule->bootEloquent();
And at the beginning of your class file you have to import:
use Illuminate\Database\Capsule\Manager as DB;
I have just solved this problem by uncommenting $app->withFacades(); in bootstrap/app.php
Had the same issue with laravel 8. I replaced
use PHPUnit\Framework\TestCase;
with:
use Tests\TestCase;
Try uncommenting in app.php $app->withFacades();
Do not forget to call parent::setUp(); before.
fails
public function setUp(): void {
Config::set('something', true);
}
works
public function setUp(): void {
parent::setUp();
Config::set('something', true);
}
One random problem using phpUnit tests for laravel is that the laravel facades have not been initialized when testing.
Instead of using the standard PHPUnit TestCase class
class MyTestClass extends PHPUnit\Framework\TestCase
one can use
class UserTest extends Illuminate\Foundation\Testing\TestCase
and this problem is solved.
I got this error after running:
$ php artisan config:cache
The solution for me was to delete the /bootstrap/cache/config.php file. I'm running Laravel 5.5.
The seems to arise in multiple situation, and not just about facades.
I received the following message while running tests using PHPUnit v.9.5.4, PHP v.8.0.3 and Lumen v. 8.2.2:
PHP Fatal error: Uncaught RuntimeException: A facade root has not
been set. in path_to_project/vendor/illuminate/support/Facades/Facade.php:258
And that happened although I had apparently already configured my app.php to enable facades ($app->withFacades();), still I received this error message whenever I tried to run tests using Illuminate\Support\Facades\DB. Unfortunately, none of the other answers helped me.
This error was actually been thrown due to my configs in phpunit.xml, which didn't point to my app.php file, where I actually enabled facades.
I just had to change
<phpunit (...OTHER_PARAMS_HERE) bootstrap="vendor/autoload.php">
to
<phpunit (...OTHER_PARAMS_HERE) bootstrap="bootstrap/app.php">
Hope it helps.
wrong way
public function register()
{
$this->app->bind('Activity', function($app)
{
new Activity;
});
}
right way 👍
public function register()
{
$this->app->bind('Activity', function($app)
{
return new Activity;
});
}
---------------------------------- don't forget return
Upgrade version for php, I encountered this error while calling the interface.
$ php artisan config:cache
Deleting the /bootstrap/cache/config.php file is a very effective way.
In my project, I managed to fix this issue by using Laravel Dependency Injection when instantiating the object. Previously I had it like this:
$class = new MyClass(
new Client(),
env('client_id', 'test'),
Config::get('myapp.client_secret')
);
The same error message happened when I used Laravel env() and Config().
I introduced the Client and env in the AppServiceProvider like this:
$this->app->bind(
MyClass::class,
function () {
return new MyClass(
new Client(),
env('client_id', 'test')),
Config::get('myapp.client_secret')
);
}
and then instantiated the class like this:
$class = app(MyClass::class);
See more from https://laravel.com/docs/5.8/container .
In my case, for a while a ran a PHP project in PHP version 8, and that time I used some PHP 8 features like param definition and method's multiple return type declarations supported by only PHP 8 and above. When I downgraded from PHP 8 to PHP 7.4 I faced this issue. After removing the return types and param hinting the problems are gone.
Tested on Laravel 8.78
tests/bootstrap.php
<?php
use Illuminate\Foundation\Bootstrap\RegisterFacades;
use Illuminate\Foundation\Bootstrap\LoadConfiguration;
require_once __DIR__ . '/../vendor/autoload.php';
$app = require_once __DIR__ . '/../bootstrap/app.php';
(new LoadConfiguration())->bootstrap($app);// <------- Required for next line
(new RegisterFacades())->bootstrap($app);// <------- Add this line
Here is yet another instance of this error, happened to me after upgrading Laravel 8 to 9.
I had feature tests with a #dataProvider to supply data to those tests. Some of the data supplied by the data provider methods came from an application service. It was being initialised like this:
/**
* #dataProvider myDataProvider
*/
public function testSomeStuff(...)
{
...
}
public function myDataProvider()
{
$myService = app(Service::class); // This is trouble
return [
['test1_data' => $myService::SOME_CONSTANT],
[...],
...
];
}
This worked under Laravel 8, but not in Laravel 9. All other solutions listed in this SO thread were checked and were correctly set up.
The problem is that the application is not being inititialised until after the data provider method is run. It was presumably initialised before this stage in the Laravel 8 install. So app(Service::class) was failing due to it using facades internally.
One workaround could be to force the application to initialise earlier, in the data provider function: $this->createApplication(). I would not recommend this due to potential side effects of the test parts running in the wrong order, though it does appear to work when I tried it.
Best solution is to avoid accessing any part of the application functionality in the data provider methods. In my case it was easy to replace $myService::SOME_CONSTANT with MyService::SOME_CONSTANT after making sure those constants were public.
Hopefully this will help somebody suddenly hitting this problem running feature tests after a Laravel 9 upgrade.
If you recently upgrade Laravel on Homestead & VirtualBox environment or do not find any reason that causing please be sure your Vagrant is up to date.
Referance
I had Taylor lock this thread. The past several replies have restated the solution, which is to Upgrade to Virtualbox 6.x, the thread is locked to prevent other issues that are not related from being dogpiled on here.
#melvin's answer above works correctly.
In case someone is wondering about it, the mistake people do is to choose Yes when VSCode asks them if they are making a Unit Test. Remember, Unit Tests should really be unit tests, independent of other application features (models, factories, routes; basically anything that would require the Laravel app to be fired up). In most scenarios, people really actually want to make Feature Tests and therefore should answer No to the above question. A feature test inherits from Tests\TestCase class (which takes care of firing up Laravel app before running the test) unlike unit tests that inherit from the class PHPUnit\Framework\TestCase which use just PHPUnit and are therefore much faster.
credit with thanks to #Aken Roberts's answer here.
From Laravel Documentation: Generally, most of your tests should be feature tests. These types of tests provide the most confidence that your system as a whole is functioning as intended.

Laravel 5 maintenance mode turn on without artisan

Is there any possibility to turn on and turn off Laravel 5 maintenance without php artisan up and down commands when my website is being hosted ?
What I've done:
Route::get('site/shutdown', function(){
return Artisan::call('down');
});
Route::get('site/live', function(){
return Artisan::call('up');
});
The first route is working fine. But when I call site/live the site still is shuted down. What can cause this problem ?
If your project is already down, you cannot call another function.
What happens after you run php artisan down is that it creates a file named down inside storage/framework. After running php artisan up the file is removed.
You can create the file manually inside storage/framework. It will down your project. When you want to take your project live again, just remove the file.
I think the right answer is missing here..
You could add your route to app/http/middleware/CheckForMaintenanceMode.php
protected $except = [
//here
];
So It never would be off.
when you run artisan down. site is not available so when try to call up, your IP can't access site.
you must call down with your IP exception.
php artisan down --allow=127.0.0.1 --allow=192.168.0.0/16
or add ::1 to local.
to make that in route without command
try to save this command in specific one and call it.
Laravel 8 introduced secret in maintenance mode, in which you can bypass the maintenance mode by providing a secret, then your Artisan::call would work.
You could add your routes to the $except var in CheckForMaintenanceMode middleware to bypass the check. Then your site/live route would work just fine.
In order to make your site live again using an url, you can create a live.php file which you put in laravel's public folder and then visit http://your.domain/live.php .
In the live.php file you need something like this: (check your projects directory structure if you don't use the default public folder!)
<?php
unlink(dirname(__FILE__) . "/../storage/framework/down");
header("Location: your.domain");
die;
just put
Artisan::call('up');
without route function.

Resources