So I have an interface I called iCron
namespace App\Console\CronScripts;
interface iCron{
public static function run($args);
}
I also have a class that uses this called UpdateStuff
class UpdateStuff implements iCron{
public static function run($args = NULL){
//I do api calls here to update my records
echo "Begin Updating Stuff";
}
}
So inside the Kernel I have:
use App\Console\CronScripts\UpdateStuff;
class Kernel extends ConsoleKernel{
protected $commands = [];
protected function schedule(Schedule $schedule){
$schedule->call(UpdateStuff::run(NULL))->dailyAt('23:00');
}
}
Which as it says I want to call the run function of UpdateStuff daily at 11PM. However the problem, is that it's calling the run function every time I use:
php artisan migrate
Anyone have any ideas why this is happening?
Thanks in advance!
EDIT: So I found where it's calling the schedule function,
vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php
This calls the defineConsoleSchedule() function which in-turn runs $this->schedule($schedule); Then for some reason, UpdateStuff::run($args) is executing even though It's not 11PM
I figured it out! So for anyone who is confused, the cron scheduler needs a Closure or a string that points to a static function with no parameters. Here's what I came up with:
class Kernel extends ConsoleKernel{
protected $commands = [];
protected function schedule(Schedule $schedule){
//This calls the run function, but with no parameters
$schedule->call("App\Console\CronScripts\UpdateStuff::run")->dailyAt('23:00');
//If you need parameters you can use something like this
$schedule->call(function(){
App\Console\CronScripts\UpdateStuff::run(['key' => 'value']);
})->dailyAt('23:00');
}
}
Hope This helps someone!
Related
I'm working on a project running an old version of Laravel (5.6). There's a lot of custom artisan commands in this project. Some of those commands should create a summary on the end of the execution. My first idea was to create a parent class, and all the commands extend from this class, something like:
<?php
abstract class ParentCommand extends Command
{
abstract protected function doYourStuff();
abstract protected function prepareSummaryData();
final public function handle()
{
$this->doYourStuff();
$this->createSummary($this->prepareSummaryData());
}
final protected function createSummary($data)
{
// Summary stuff in here...
}
}
But the problem is that Laravel does DI in the handle method, so the handle method in child classes could have a different signature, which is not allowed.. :(
Any idea of how to run something after the handle() method is executed?
What about using a trait ?
trait Summary
{
protected function createSummary($data)
{
// Summary stuff in here...
}
}
class SomeCommand extends Command
{
use Summary;
public function handle()
{
//do stuff
//prepare data to summarize
$this->createSummary($data);
}
}
I am trying to implement an Interface into a Job but having no luck. Is it possible to implement an interface / repository within the public construct and use said interface in the handle() method of the Job?
The error I am getting is as follows:
Argument 1 passed to App\Jobs\OrderCreate::__construct() must be an instance of App\Http\Interfaces\OrderInterface, string given, called in /Users/Panoply/Sites/stock-sync/app/Http/Controllers/StockController.php on line 31
Below is a basic setup of what I am trying to achieve.
Stock Controller:
public function test(){
dispatch(new OrderCreate('hello'));
}
OrderCreate Job:
protected $order;
protected $test;
public function __construct(OrderInterface $order, $test)
{
$this->order = $order;
$this->test = $test;
}
public function handle()
{
$this->order->test($this->test);
}
OrderRepository:
class OrderRepository implements OrderInterface
{
public function test($data) {
error_log($data);
}
}
OrderInterface:
public function test($data);
I have had no troubles implementing this pattern into my controllers and commands but I can't seem to get it working on a Job.
Nevermind, the issue was I shouldn't of been calling the interface within the __construct() but instead within handle()
Editing for more detailed explanation.
The __construct() of a Laravel / Lumen Job from what I can tell only accepts data and thus implementing an interface within the __constuct() will cause my above error to be thrown.
In order to use an Interface within a job, you will need to call your interface within the handle() function.
As an example, the following will NOT work within a Job class:
protected $test;
public function __construct(InterfaceTest $test)
{
$this->test = $test;
}
This is because the Job construct does not take in Interfaces, it only takes in the data you pass in from the dispatch call. In order to use your Interface within a job, you need to call the interface within the handle() function and then it will succeed and work, example:
public function handle(InterfaceTest $test)
{
$test->fn();
}
This seems to only be the case when implementing on a Job. In most cases when you require an interface within a Controller or Command, you will implement within the __construct().
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.
Look I have a class that looks like this, i want to cache some info every day in a cron job with this method cacheTopFilters in laravel 5.1
<?php
namespace namescape/of/the/class;
class FilterTypeCacheService extends BaseService implements IFilterTypeCacheService
{
private $searchFilterService;
private $filterCacheHandler;
function __construct(SearchFilterService $searchFilterService, IFilterTypeCacheHandler $filterCacheHandler){
$this->searchFilterService = $searchFilterService;
$this->filterCacheHandler = $filterCacheHandler;
}
public function cacheTopFilters($type,$keyValuePair,$limit){
$filters = $this->searchFilterService->getAllFilters($type,$keyValuePair);
$this->filterCacheHandler->deleteFiltersBulkFromCache();
$this->filterCacheHandler->SaveFiltersBulk($filters,$type);
}
public function getTopFilters(){
$topFilters = $this->filterCacheHandler->getCachedTopFilters();
return $topFilters;
}
}
As they have dependency injection how can i accomplished to called that method on the app/console/kernel on the schedule method?
You want to take a look at Task Scheduling:
https://laravel.com/docs/5.1/scheduling#defining-schedules
In the App\Console\Kernel class, inside the schedule function, you can schedule anything at all like this:
$schedule->call(function () {
doSomething();
})->daily();
Assuming you have the scheduler setup (system cron job every minute) you should be all set.
If you have a class you need to instantiate, with dependencies injected, you can always use the global app() helper function that Laravel gives you:
$schedule->call(function () {
app(\namespace\of\the\class::class)->cacheTopFilters(...);
})->daily();
That's assuming that Laravel knows how to handle your dependencies. I see that one of your dependencies is a contract (interface) so I'm assuming you've already bound the concrete instance in the Laravel IoC.
I have a job in my Laravel project (v.4.2). which is used for inserting data into database. The class named "ProductUpdate". I use Amazon SQS for queue service.
What makes me confuse now is, when I changed the code in class "ProductUpdate",
it seems that the job is running by using old version of the class.
I even deleted all lines of code in the class but the jobs can still be able to run ( it stills inserts data).
Following is the job class.
The file of this class is at app/jobs/ProductUpdate.php
In my understanding, job class is the only place that will be called from queue, but why it can still be able to run when I deleted all the codes?
<?php
/**
* Here is a class to run a queued item sent from SQS
* Default method to use is fire()
**/
class ProductUpdate
{
public function fire($job, $data)
{
// Disable query log
DB::connection()->disableQueryLog();
// Set the job as a var so it will be used across functions
$this->job = $job;
$product = Product::find($productID);
if($product->product_type != 18) {
// Call the updater from library
$updater = App::make('Product\PriceUpdater');
$updater->update($product);
}
// Done and delete
$this->success();
}
private function success()
{
$this->job->delete();
}
private function fail($messages = array())
{
Log::error('Job processing fail', $messages);
$this->job->delete();
}
}
Your problem is related to cache.
Run this command in terminal to remove all cached data.
php artisan cache:clear
other way:-
Illuminate\Cache\FileStore has the function flush, so you can also use it:
Cache::flush();
This link will also help you :)