Laravel 5.5 Queues & Jobs : job is never executed - laravel

I'm fairly new to Lumen (Laravel), and I'm currently digging the concept of Queues, Jobs & Scheduled Tasks.
I would like to store in a Queue some Eloquent models, when I receive them from API calls. Then, I want to create a scheduled task which runs a daily Job, to fetch all those models in Queue and then send a report email.
I went the database storing way for Queues.
So I added the QUEUE_DRIVER=database key in my .env file and my queue.php config file looks like this :
<?php
return [
'database' => [
'connection' => 'my_db_connection',
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90
]
];
I ran the php artisan queue:table command to create the migration file and ran migration to create my table. I have a table jobs, with the right intended fields.
I created a class, implementing ShouldQueue :
class ProcessDeliveryOrders implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $deliveryOrder;
public function __construct($deliveryOrder)
{
$this->deliveryOrder = $deliveryOrder;
}
public function handle()
{
// $this->deliveryOrder->save(); ?
}
}
As sub-question here is about how this class is working : Can it stores automatically the Eloquent model when it receives it in it's constructor ? to me the handle method is called when the object is retrieved by the Job, but I can be wrong and it's used to store the object ?
Then, I created a MailingJob : it's goal is to aggregate all the ProcessDeliveryOrders stored daily, and create an email from them :
class SendDeliveryEmailJob extends Job
{
public function __construct()
{
//
}
public function handle()
{
// DeliveryOrder is my Eloquent Model
$deliveryOrders = DeliveryOrder::query()
->whereBetween('createdAt', [strtotime('today midnight'), strtotime('today midnight')])
->get();
$mail = Mail::to(config('admin.emails'));
$mail->send(
new DeliveryOrderReportMailTemplate([
'deliveryOrders' => $deliveryOrders
])
);
}
}
And in my Kernel.php, I have added the following line in function schedule() :
// everyMinute for test purposes only
$schedule->job(new SendDeliveryEmailJob())->everyMinute();
As I'm using Lumen, I don't have the exact same process as in pure Laravel, so when I receive a delivery order to call my dispatch, I tried both ways exposed by the Lumen doc (forced to create an instance of my Job) :
dispatch(new ProcessDeliveryOrders($deliveryOrder));
// OR
Queue::push(new ProcessDeliveryOrders($deliveryOrder));
After all this setup, I tried few commands like php artisan queue:listen or php artisan queue:work, and the command line seems to be stuck.
If I run php artisan queue:listen database I get the following looped error :
In QueueManager.php line 172:
No connector for []
I checked documentation twice, and tried the new key QUEUE_CONNECTION=database instead of QUEUE_DRIVER but it's apparently only since 5.7, and didn't worked either. Any chance you spot something I'm missing ? Thanks a lot
EDIT: When I put a logging in the SendDeliveryEmailJob constructor, and I run php artisan queue:listen, I see the echo output every 2 or 3 seconds. I've also put a log into the handle function but I never see this one called.
EDIT 2: I noticed that when I try to execute my scheduled tasks with php artisan scheduled:run, it throws an error :
Running scheduled command: App\Jobs\SendDeliveryEmailJob
In Schedule.php line 87:
Call to a member function onQueue() on null
I guess from this message, that my Job is not instanciated, but I see the constructor message displayed to it's kinda weird..

#alex QUEUE_CONNECTION=database put this in your env and your queue.php is
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],

Related

Is it possible to trace the detail of third party everytime,when the third party perform any event to our server using sentry?

I want to trace the detail of third party if any action is perform in out server by third party.Need Help.
There are several ways.
There is a wonderful package. You can check the laravel telescope.
Laravel Telescope
Also, You can add middleware to some routes that you want to save data.
In the middleware, you can save data to the database, or if you want to save data by laravel log, you can create a custom channel in config/logging.php like this:
'channels' => [
'your_channel_name' => [
'driver' => 'daily',
'path' => storage_path('logs/request/request.log'), // Your customer path
]
]
And your middleware will be like this (If you want to handle it by logs):
public function handle(Request $request, Closure $next)
{
$yourData = $request->all() // + ip and etc.
Log::channel('your_channel_name')->info($yourData);
return $next($request);
}
It handles your data by laravel log.
I hope it is useful.

Is there an tutorial for how to set up an ldap server and after to connect it with a simple laravel app?

I set up the ldap using DigitalOcean tutorial and installed AdLdap2 package and if anybody can clarify to me why on login to the ldap server still try to login with default username and password, i can't explain properly the problem if it doesn't make sense to you, can you just put here some links which helped you to set up the server and connect a laravel project with ldap
I know I'm a little late but these are my notes from when I set it up for one of my apps.
Adldap2-Laravel (NoDatabaseProvider)
Installation
Install the Adldap2-laravel package:
$ composer require adldap2/adldap2-laravel
Create the auth scaffolding:
$ php artisan make:auth
Configuration
Define the following environment variables in your .env file:
# .env
LDAP_HOSTS=[192.168.1.10]
LDAP_PORT=[389]
LDAP_BASE_DN=[DC=contoso,DC=com]
LDAP_USERNAME=[ldap#contoso.com]
LDAP_PASSWORD=[password123]
Disable the default routes if only using LDAP authentication. In your /routes/web.php file, make the following changes for Auth::routes() :
# /routes/web.php
Auth::routes([
'reset' => false,
'verify' => false,
'register' => false,
])
In your /resources/views/auth/login.blade.php file, change the label for email address to Username, remove the #error('email) section from the corresponding text input and change the name on that text input to whatever LDAP attribute you are looking users up by (samaccountname or userprincipalname) Finished text input should look something similar to this:
# /resources/views/auth/login.blade.php
<input type="text" class="form-control" name="samaccountname" value="{{ old('samaccountname') }}" required autofocus>
Create the ldap.php and ldap_auth.php file by running the following two commands:
$ php artisan vendor:publish --provider "Adldap\Laravel\AdldapServiceProvider"
$ php artisan vendor:publish --provider "Adldap\Laravel\AdldapAuthServiceProvider"
Change the user driver to use ldap instead of eloquent under providers in /config/auth.php and comment out the model below it, like so:
# /config/auth.php
'providers' => [
'users' => [
'driver' => 'ldap', // <- was eloquent, changed to ldap
# 'model' => App\User::class, // <- commented out, not using anymore
In /config/ldap_auth.php:
Change the provider from DatabaseUserProvider to NoDatabaseUserProvider:
# /config/ldap_auth.php
'provider' => Adldap\Laravel\Auth\NoDatabaseProvider::class
Change the locate_users_by under ldap to whatever field you plan to authenticate users by (samaccountname or userprincipalname)
# /config/ldap_auth.php
'ldap' => [
'locate_users_by' => 'samaccountname',
'bind_users_by' => 'distinguishedname',
],
In your /app/Http/Controllers/Auth/LoginController.php file, you must add a username() function that returns the LDAP attribute you are authenticating users by:
# /app/Http/Controllers/Auth/LoginController.php
public function username()
{
return 'samaccountname';
}
In your /config/app.php file, it's helpful to add the alias for the Adldap Facade to keep from having to type it out every time you need to access it:
# /config/app.php
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
. // scroll
. // to
. // the
. // bottom
'View' => Illuminate\Support\Facades\View::class,
'Adldap' => Adldap\Laravel\Facades\Adldap::class // <- add this
],
Usage
After successfully authenticating, if you add use Auth; in your controller with the other use contracts in the beginning of the file, you can access the authenticated user's attributes like so:
# /app/Http/Controllers/HomeController
use Auth;
public function index()
{
$user = Auth::user();
$cn = $user->getCommonName(); // assigns currently authenticated user's Common Name
return view('home')->with('cn', $cn);
// using {{ $cn }} on the home's view would output the Common Name
}
If you want to query the LDAP server for all other users, you can add use Adldap; with the other use contracts and use the query builder:
# /app/Http/Controllers/HomeController
use Adldap;
public function index()
{
$users = Adldap::search()->where('objectclass', '=', 'person')->sortBy('cn', 'asc')->get();
return view('home', compact('users'))
// use a foreach loop on the view to iterate through users and attributes
}

Lumen job dispatching done without database Queue Driver

What do I have:
Lumen service which processing particular Job
Laravel portal which sending file to that service for processing by it
Once it was using only JS and Ajax it worked almost fine - the only what I had to implement is CORS middleware. However after I moved logic to JWT (using jwt-auth package) and GuzzleHttp (I'm using it to send requests to service API) Job stopped processing throught database queue instead it running as if Queue driver being set to sync.
Following is controller which I'm calling during API call:
public function processPackageById(Request $request) {
$id = $request->package_id;
$package = FilePackage::where('id', '=', $id)->where('package_status_id', '=', 1)->first();
if($package) {
Queue::push(new PackageProcessingJob(
$this->firm,
$this->accounts,
$package
));
return 'dispatching done for ' . $id;
}
return 'dispatching not done for ' . $id;
}
where $this->firm and $this->accounts are injected Repositories for particular models. FilePackage object being created on Laravel site and both shares same database to work with.
As result no job being incerted into jobs table. When I use Postman everything is fine. However when I'm trying to send request from Laravel backend:
public function uploaderPost(Request $request)
{
// Here we get auth token and put into protected valiable `$this->token`
$this->authorizeApi();
$requestData = $request->except('_token');
$package = $requestData['file'];
$uploadPackageRequest =
$this->client->request('POST', config('bulk_api.url') .'/api/bulk/upload?token=' . $this->token,
[
'multipart' => [
[
'name' => 'file',
'contents' => fopen($package->getPathName(), 'r'),
'filename' => $package->getClientOriginalName(),
],
]
]);
$uploadPackageRequestJson = json_decode($uploadPackageRequest->getBody()->getContents());
$uploadPackageRequestStatus = $uploadPackageRequestJson->status;
if($uploadPackageRequestStatus == 1) {
$package = BulkUploadPackage::where('id', '=',$uploadPackageRequestJson->id)->first();
// If package is okay - running it
if($package !== null){
// Here where I expect job to be dispatched (code above)
$runPackageRequest =
$this->client->request('POST', config('api.url') .'/api/bulk/run?token=' . $this->token,
[
'multipart' => [
[
'name' => 'package_id',
'contents' => $package->id
],
]
]);
// Here I'm receiving stream for some reason
dd($runPackageRequest->getBody());
if($runPackageRequest->getStatusCode()==200){
return redirect(url('/success'));
}
}
}
return back();
}
Could anyone advise me what is wrong here and what causes the issue?
Thank you!
Alright, it was really interesting. After echoing config('queue.default') in my contoller it appeared that it's value indeed sync nevertheless that I set everything correctly.
Then I assumed that maybe the reason in Laravel itself and its variables. Indeed in .env file from Laravel side QUEUE_DRIVER being set to sync. After I changed it to QUEUE_DRIVER=database everything started working as expected.
Hope that will help someone in future.

Only one seed not working Laravel 5.5

all seeds are working but one throws exception
Call to undefined method Illuminate\Support\Facades\Lang::setContainer()
public function run()
{
DB::table('lang')->insert([
[
'lang_name' => 'Русский'
],
[
'lang_name' => 'English'
],
[
'lang_name' => 'Empty'
]
]);
}
can you try changing the Seeder class name to something else? Like LangSeeder ? And not Lang?
Looks like Lang is a class name used by Laravel already and seeder classes are in root namespace!

Use Laravel seed and sql files to populate database

I got several .sql files of countries, states and cities of the world from github. How can I run them with Laravel's seed files to populate those tables in my database?
Add DB::unprepared() to the run method of DatabaseSeeder.
Run php artisan db:seed at the command line.
class DatabaseSeeder extends Seeder {
public function run()
{
Eloquent::unguard();
$this->call('UserTableSeeder');
$this->command->info('User table seeded!');
$path = 'app/developer_docs/countries.sql';
DB::unprepared(file_get_contents($path));
$this->command->info('Country table seeded!');
}
}
I found a package that creates seed files from database tables and rows. It currently supports Laravel 4, 5, 6, 7, 8 and 9:
https://github.com/orangehill/iseed
In the end, it's basically as easy as this:
php artisan iseed my_table
or for multiple occasions:
php artisan iseed my_table,another_table
As used by other answers, DB::unprepared does not work with more complex SQL files.
Another better solution would be to use the MySQL cli directly inside a process:
$process = new Process([
'mysql',
'-h',
DB::getConfig('host'),
'-u',
DB::getConfig('username'),
'-p' . DB::getConfig('password'),
DB::getConfig('database'),
'-e',
"source path/to/schema.sql"
]);
$process->mustRun();
2022 Simplified answer from Andrew Koper :
class WhateverSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$file_path = resource_path('sql/whatever.sql');
\DB::unprepared(
file_get_contents($file_path)
);
}
}
Fun fact: 60,000 rows took me 50s to import from JSON file where this is 400ms.
#Andre Koper solutions is understandable, but sadly it doesn't work for me.
This one is a bit confusing but atleast works for me.
So instead of using DB::unprepared, I use this:
// DatabaseSeeder.php
class DatabaseSeeder extends Seeder {
public function run()
{
// Set the path of your .sql file
$sql = storage_path('a_id_territory.sql');
// You must change this one, its depend on your mysql bin.
$db_bin = "C:\wamp64\bin\mariadb\mariadb10.3.14\bin";
// PDO Credentials
$db = [
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'host' => env('DB_HOST'),
'database' => env('DB_DATABASE')
];
exec("{$db_bin}\mysql --user={$db['username']} --password={$db['password']} --host={$db['host']} --database {$db['database']} < $sql");
}
}
Then while migrating database just add --seed
php artisan migrate:refresh --seed
or
php artisan migrate:fresh --seed
Tested on Laravel 7.0.x

Resources