I'm trying to schedule an email to remind users who have to-do tasks due tomorrow. I made a custom command email:reminder. Here is my code in custom command:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Todo;
use Illuminate\Support\Facades\Mail;
class SendReminderEmail extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'email:reminder';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Remind users of items due to complete next day';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
//
/*
* Send mail dynamically
*/
/*
* hardcoded email
*/
Mail::queue('emails.reminder', [], function ($mail) {
$mail->to('example#email.com')
->from('todoreminder#gmail.com', 'To-do Reminder')
->subject('Due tomorrow on your To-do list!');
}
);
$this->info('Reminder email sent successfully!');
}
}
I hardcoded the email for now to test it, but when I ran php artisan email:reminder, I got an exception of
[InvalidArgumentException]
Only mailables may be queued.
I then checked Laravel's documentation, but Task Scheduling and Email Queue are 2 separate topic.
How can I achieve sending email queue with task scheduling in Laravel
5.6 please?
Also how can I pass data, i.e. to-do items in database into my email
view please?
Any help is greatly appreciated!
Using the console kernel to schedule queued jobs is easy to do. Laravel offers several wrapper methods that make the cron integration trivial. Here's a basic example:
$schedule->job(new SendTodoReminders())->dailyAt('9:00');
You should create a command which does exactly as you described, but without the scheduling. You can use the crontab for scheduling or some other task scheduler.
Have you followed Laravel's documentation about mailing? https://laravel.com/docs/5.6/mail
Once you get to the Sending Mail section, you should not create a controller but a command instead.
When that command works, add it to the task scheduler (eg. crontab) to run on a daily basis.
Mail::queue('emails.reminder', [], function ($mail) {
$mail->to('example#email.com')
->from('todoreminder#gmail.com', 'To-do Reminder')
->subject('Due tomorrow on your To-do list!');
}
);
is deprecated since Laravel 5.3. Only the Mailables can Queued and it should implement the ShouldQueue interface.
For running jobs you have to configure the queue driver and run php artisan queue:work
Related
I am developing a Laravel application for a client company of mine. That company has a server guy. In the middle of the development process, I asked him to set up a server for the application. But he set up a server without any kind of automated deployments procedure instead he gave me a C-Pannel to deploy the changes manually. The application became so complex and now manual deployments became a very tedious task. I am manually building js and css and uploading them to the server. After a heated argument with him, I finally made him work on automated deployments. Instead of properly putting deployments he has put it this way.
<?php
//app/Console/Commands/GitPull.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class GitPull extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'git:pull';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Get updates from git server';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
exec('git pull origin master');
}
}
<?php
app/Console/Kernel.php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
Commands\GitPull::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('git:pull')
->everyMinute();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
Basically he has put a scheduler to execute git pull every minute. Is this the correct way to put deployments? What are the drawbacks in this way? Do the deployments have to be dependent on the application? Is it possible to add automated deployments without the help of the laravel framework? I am not very familiar with dev-ops.
Also, my source code is in bitbucket. I am ready to answer any questions regarding this. Thanks in advance.
I certainly would not use a Laravel command to run deployments. Automated deployments can be as simple or complex as needed, but here are some things I expect a build agent to do:
Listen to changes to master to do a production deploy
Run tests (and alert and stop deployment if they fail)
Build my static assets (js/css/etc)
Copy code to server (several ways to do this)
Run migrations
Restart queues so they are running with latest code
Since you're on bitbucket you could look into pipelines to do your ci/cd.
I'm developing the app for the customer and he wants to start some jobs in special time
I must run it in jobs, that's right?
for example, he wants to publish a post have 2 status published or waiting
and in send page, he can set time for publish post
how I can develop this in jobs?
ScanJob::dispatch($property->Name, $property->Owner, $Scan->id)->delay(Carbon::now()->addHour(Carbon::now()->diffInHours($Time)));
it's my first try
get diff time in hours and add it from delay
There are basically two ways via which you can solve your problem:
Create a Laravel Artisan command(you can use other methods also that Laravel provides, but I found Artisan to be fun and more flexible, helps avoid the rework) and schedule it accordingly.
Create a Queued Job and dispatch it for some later time, but it has some limitation like, the Amazon SQS queue service has a maximum delay time of 15 minutes.
Now, what is to be done:
In my opinion, you should use Solution 1 as it is more flexible and gives you more control.
Queues are used for 2 things. First, ideally, the task you want to perform should be done in the next 30-45 minutes. Second, the task is time intensive and you don't want to block the thread because of that.
Now the FUN part.
Note: You need not worry, Laravel will perform the majority of the steps for you. I am mentioning each and every step for the sake of not skipping the knowledge.
Step 1: Run the following command to create an Artisan Console Command(Remember to be in your project's root path.):
php artisan make:command PublishSomething
The command will now be available for further development at app/Console/Commands.
Step 2: You will see a handle method inside the Class like following, this is where all of your logic will exist.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class PublishSomething extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'something:publish';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Publishes something amazing!';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
//
}
}
Step 3: Let's add some logic inside our handle method
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->info('Publishing something cool!');
// you can add your own custom logic here.
}
Step 4: After you have added your logic, now we need to test it, you can do so like:
php artisan something:publish
Step 5: Our function is running all fine. Now we will schedule the command. Inside app/Console you will find a file Console.php, this class is responsible for all task scheduling registration, in our case.
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* #return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
Notice the schedule function here, this is where we will add the schedule logic.
Step 6: Now we will schedule our command to run every 5 minutes. You can change the time period very easily, Laravel provides some pre-made frequency options, and you have your own custom schedule also.
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('something:publish')->everyFiveMinutes(); // our schedule
}
Step 7: Now, Laravel's task scheduler itself is dependent on Cron. So to start the schedule, we will add the following file to our crontab.
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
That's it! We are done. You have created your own custom command and scheduled it for every 5 minutes.
You can learn more about Laravel Artisan Command & Laravel Task Scheduling.
Hope it helps!
I am developing a laravel 5.7 application.
I have created a command that should setup my database:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
class TestSetupCommand extends Command
{
protected $signature = 'test:data';
protected $description = 'Basic Setup for Test Data';
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
Artisan::call('migrate:refresh', ['--seed' => '']);
Artisan::call('basis:cc');
Artisan::call('tick:exchange');
$this->info("DB freshly setup: DONE");
$this->info("Coin: DONE");
$this->info("Exchange Scrapped: DONE");
}
}
My problem is that each command takes several minutes to run through. In total it costs me 25 minutes to fill the whole database with data.
I would like to run the commands only for 1 minutes each and kill them afterwards.
Any suggestions how to accomplish this within my laravel command?
I think the best way to do this is to extract these commands into background job. This artisan command then becomes code to queue up that new job (or jobs).
Why? It's very easy to configure jobs to timeout after x amount of time, by overriding a value like so:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* The number of seconds the job can run before timing out.
*
* #var int
*/
public $timeout = 120;
}
Also, why are you refreshing the database? That seems.... like a crazy idea unless this is purely an analytics platform (no user data at all). It's probably a bad thing if that refresh command times out - you may look into job chaining so that the refresh command is guaranteed to succeed, then the other commands (new jobs now) have set timeouts.
Trying to run a function in Laravel that's quite large and fetches a lot of data from Google Places API and stores parts in my database as new entries in a table. The problem is it auto-discovers new entries for me near my current entries, and that creates more jobs.
When I just access the command via GET it times out eventually. I've tried running it as a scheduled command with Redis but to be frank I can't seem to figure out how it works. I've created a job, I tried to queue it with dispatch, but then it tries to run it immediately right now and it times out eventually again.
How do I run this large task without it pausing my entire server?
Thanks
Zach
I is really simple and you do not need to stop server. It is just CRON job. Use Laravel Schedule.
When using the scheduler, you only need to add the following Cron entry to your server.
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
Class example:
namespace App\Console;
use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
}
More: https://laravel.com/docs/5.6/scheduling
Nice video about laravel scheduling: https://www.youtube.com/watch?v=mp-XZm7INl8
I am building web app in PHP which is used to schedule tasks in the future. In the background I am supposed to Poll the database every 2 min to see if there is any upcoming task. How do I implement polling. Javascript solution is not helpful as the user can be on any of the pages on the webapp, but the system should keep pooling the DB.
Cron is one way but still I have to poll the database to create a cron job. What is the best way to implement it?
Thanks
Create a cron job that is executed once every X minutes and make that job check the DB. If there is a new upcoming task, just make the job launch it.
Create an 'execute:tasks' artisan command, so you can poll your database whenever you need to execute your tasks. You should be able to run it this way:
php artisan execute:tasks
Your command will call some controller action (or a class method) to poll the database and find if there are tasks available to be executed.
Then you just need to create a cron job that will execute that artisan command every 2 minutes:
*/2 * * * * php artisan execute:tasks
This is an example of Artisan command:
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class ExecuteTasksCommand extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'execute:tasks';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Find and execute available tasks.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return void
*/
public function fire()
{
(new ExecuteTasksClass)->findAndExecute();
}
}
You just have to name this file something like app/commands/ExecuteTasksCommand.php
And add this to app\start\artisan.php:
Artisan::add(new ExecuteTasksCommand);