peppeocchi / php-cron-scheduler Goto Github PK
View Code? Open in Web Editor NEWPHP cron job scheduler
License: MIT License
PHP cron job scheduler
License: MIT License
I have the following set up in a PHP class:
class Cron {
public function run() {
$config = [
"emailFrom" => "[email protected]",
"emailTo" => "[email protected]"
];
$scheduler = new Scheduler($config);
$scheduler->call('myFunc')->every()->minute()->output(APPPATH .'logs/cron.log');
}
function myFunc() {
echo 'Message called from cron');
}
}
I have a cron setup to call this every minute, however myFunc() never gets called. I can see a run method in the Scheduler class which never gets called. Am I missing something obvious in my setup?
The scheduler currently supports a then
method, a callback executed after the job runs.
It seems a good idea to have a before
method that's being executed before the job runs.
Is it possible to setup a schedule to run every 10 seconds or lets say 30 seconds?
I have a php script I want to run once a month or every day, depending on the value of certain values in a database.
I have no problem getting the variables into scheduler.php, but can't seem to write a function that will accomplish the above.
I've tried various ways of using the function lines you present, but can't get the result I need. What is the best way to do this?
It's not clear from the instructions if I should chain the command all into one thing, but maybe that's the key, like this, which I've seen in another cron scheduler:
$schedule = new Scheduler();
$schedule->php('filetorun.php')
->at("10 10 10 * *");
->when(function() {
if ($strcron) { return true; }
});
->output(['logs/cron_renewalemail.log'])
->run();
Thank you!
please, How can i display all jobs in crontab ?
Here is my schedule.php content:
require_once __DIR__ . '/vendor/autoload.php';
use GO\Scheduler;
$scheduler = new Scheduler();
$scheduler->call(function () {
echo "Hello";
return " world!";
})->everyMinute()->output('/tmp/my_file.log');
$scheduler->run();
I executed $ php schedule.php
. As expected, the file /tmp/my_file.log was created and had Hello World! in it.
Immediately after that I emptied out /tmp/my_file.log and ran $ php schedule.php
again. Since one minute has not passed, the /tmp/my_file.log should NOT get filled with Hello World! but it did. Why did it?
Would it be possible to circumvent this scheduling method where it allows only at least every minute and is able to adjust to run for example every 10 seconds?
Hello,
Thanks you for all this work. It's awesome.
Are you aware that mtdowling/cron-expression is falling ? According to http://ctankersley.com/2017/10/12/cron-expression-update/ , it seems there is a complete rewrite.
The prototype of CronExpression::factory seems to remain the same in the new project (dragonmantank/cron-expression)
OLD : https://github.com/mtdowling/cron-expression/blob/master/src/Cron/CronExpression.php
NEW : https://github.com/dragonmantank/cron-expression/blob/master/src/Cron/CronExpression.php
I guess there is no problem to update your composer.json to replace "mtdowling/cron-expression": "~1.0" by "dragonmantank/cron-expression/": "~2.0"
Best regards
Vincent
First, this is very helpful -- thanks for putting it out!
My server is in UTC, so I'm passing custom timezone to Scheduler as "America/New_York" but it's not taking. Not affected by every()->hour('00')
calls but every()->day('9:30')
is.
any ideas?
If you call $scheduler->php('script.php');
and there is no script.php present, the job will be listed under executed jobs and not under failed jobs. Thats really bad.
I have a cron job set up like so, following the directions. It's not supposed to fire until the 12th of the month, and this is the 10th:
$renewalemail = new Scheduler();
$renewalemail->php('cron_renewalemail.php')->at('15 10 12 * *');
$renewalemail->run();
But it's firing anyway. What am I doing wrong?
Thanks.
It'd be great to have the ability to insert a job output directly in the message body, not as an attachment. I receive lots of emails with the output which is always a short plain text and it's quite inconvenient to open every single one.
Besides, it looks like the body specified in the job is always replaced with "Cronjob output attached" defined inaddPart
method in Mailer.php
$scheduler->configure([ 'email' => [ 'subject' => 'Test subject', 'body' => 'Test body', ] ]);
/src/GO/Traits/Mailer.php
->setBody($config['body'], 'text/html')
->addPart('<q>Cronjob output attached</q>', 'text/html');
what would be the best way for me to define a try catch on each task so that one task is not harmed by the other
<?php
$this->scheduler->call(function () use (&$skyhub) {
$skyhub->invoice();
})->at('0,30 * * * *')->then(function ($output) use (&$logger) {
if (!empty($output)) {
$logger->error("Skyhub Invoice - {$output}");
}
});
$this->scheduler->call(function () use (&$skyhub) {
$skyhub->shipped();
})->at('0,30 * * * *')->then(function ($output) use (&$logger) {
if (!empty($output)) {
$logger->error("Skyhub Shipped - {$output}");
}
});
Was getting this exception when commands were triggered via cron/php-cron-scheduler, but not when I ran them manually.
Found this thread detailing the same issue, but with Dispatcher: Indatus/dispatcher#68
My solution w/ php-cron-scheduler was to specify usr/bin/php-cli
instead of php
in the cron command:
So this:
php /home/thewcc/www/abc/artisan "abc:run-all-scheduled-jobs" > /dev/null
Became this:
/usr/bin/php-cli /home/thewcc/www/abc/artisan "abc:run-all-scheduled-jobs" > /dev/null
Noting here just in case anyone else comes across a similar problem.
I have the following being executed on a cron job every minute
$scheduler = new GO\Scheduler([
'email' => [
'subject' => 'Hourly Email History From Attendee Scheduler',
'from' => ADMIN_EMAIL,
'body' => 'This is the daily visitors count',
'transport' => $transport,
'ignore_empty_output' => true,
]
]);
$scheduler->call(
function($run, $per_minute, $trottle) use ($emailer, $logger) {
if($emailer->sendAttendeeEmails($run, $per_minute, $trottle) == -1)
{
trigger_error(sprintf('These emails failed to send %s' , join(',', $emailer->get_failed())), E_USER_WARNING);
}
echo "Total emails send {$emailer->get_sent()}";
echo "{$logger->dump()}";
},
[
$NUM_EMAIL_PER_RUN,
$EMAILS_PER_MINUTE,
$NUM_SECS_PAUSE_RUN
],
'SchedulerEmail'
)->at("*/2 * * * *")->output('run.log')->email([
[
'[email protected]' => 'Admin Store'
],
'[email protected]'
]);
// Let the scheduler execute jobs which are due.
$scheduler->run();
The above code uses SwiftMailer to execute batch emails every 2 minutes then email and save to a file. While the job runs as expected I get neither an email nor an output file
I'm running PHP 7.0.32 using 2.*
Is it that I cannot run both or is there something else I'm missing here
UPDATE
I'm able now get the logs but not the emails
I am not running the scheduler from cron job.
I start it manually by running this command
php index.php
This is my index.php file :
require_once '/var/www/html/cron/vendor/autoload.php';
use GO\Scheduler;
$myfile = fopen("/var/www/html/cron/newfile".date('Y-m-d H:i:s').".txt", "w") or die("Unable to open file!");
$txt = "John Doe\n";
fwrite($myfile, $txt);
$txt = "Jane Doe\n";
fwrite($myfile, $txt);
fclose($myfile);
$scheduler = new Scheduler();
$scheduler->php('/var/www/html/cron/index.php')->everyMinute();
I want to run this file again but it is not running not even any error in console. nothing,
When i run this manually by php index.php
command newFIle.text
is created successfully.
It should be created every minute bcz of this line $scheduler->php('/var/www/html/cron/index.php')->everyMinute();
but it is not.
Kindly let me know if i am missing something here
is there any way to use this library to run tasks in less time every minute? ie every 15 seconds for example?
If the worker is running in the background, is it possible to add jobs from another file? Both files are in the same directory, but one file worker.php
will run in the background and execute jobs. Another file is a interface for the scheduler, so the web application can add jobs to it whenever it wants.
Also how do you remove jobs?
Thank you in advanced for all the help! 👍
Hi,
Very nice package. Can you add an option to avoid overlapping a job?
Hello,
First of all thanks for PHP Cron Scheduler, I feel that it will simplify my life (but not yet ;)).
However, I can not make the scheduler work, despite reading the readme carefully.
Here is my file scheduler.php
<? php require_once __DIR __. '/ vendor / autoload.php';
use GO \ Scheduler;
$ scheduler = new Scheduler ();
$ scheduler-> call (function () {
echo "Hello";
return "world!";
}) -> output ( 'myfile.log');
$ Scheduler-> run (); ?>
And here's what the command crontab -l sends me back (after adding in my crontab):
* * * * * / usr / bin / php /Applications/MAMP/htdocs/test/scheduler.php 1 >> / dev / null 2> & 1
myfile.log file is already creating and even after waiting for many minutes it remains desperately empty.
Note that it works when I do directly in terminal:
/usr/bin/php /Applications/MAMP/htdocs/test/scheduler.php
What's wrong with my approach?
Thanks for your help !
I'd be quite handy to have the ability to prevent a job from being executed if the condition in before
method it's not met.
Is there a way to call the method of the current object or another object?
Thanks for a pretty cool, easy-to-use, scheduler.
It took me some time to debug this issue.
We are using your script to schedule raw commands using CronExpressions like ->at("0 3 * * *")
. Some of our commands are with doNotOverlap() others are not. We have a total of 20 commands scheduled.
I have observed that when doNotOverlap() is set you, always set the job to run in foreground even if I haven't set the explicitly on the job.
The problem is that the CronExpression isDue()
calculates the execution time always using strtotime("now"). Because the execution could take more than one minute and it runs in foreground, the next job picked from the list won't be executed because the isDue will return false, it's not on time anymore because isDue will use now() and not the time the job was scheduled.
Solutions:
1.) I don't understand why you force nonOverlapping jobs to run in foreground. You should remove that line because it doesn't make much sense to me.
2.) You should rewrite your isDue function to use the time when the job was scheduled and not current time which could be several minutes later because of the non-overlapping jobs.
/**
* Check if the job is due to run
*
* @return bool
*/
public function isDue()
{
return $this->execution->isDue(date("c", $this->time)) && $this->truthTest === true;
}
I think both 1.) and 2.) solutions should be applied on your script.
In the Job.php file
At line 311
$compiled = '(' . $compiled . ') > /dev/null 2>&1 &';
Does not support windows
Change to
$compiled = $compiled.' 2>&1';
I'm not good at English
Please understand
Hi,
thanks for this library. It would be nice to store exception on failed jobs for debugging. Now you can only access exception message via outputSchedule, which is not enough to debug complex jobs.
Should I send PR?
Will there be support for Swiftmailer >=6.0?
I ran into this issue yiisoft/yii2#7848 and had to use 5.4.0 to make it work.
Schedule ping url (optionally pass parameters)
I'm facing this issue, I'm a newbie to php, help needed
PHP Fatal error: Uncaught Error: Class 'GO\Scheduler' not found in D:\scheduler.php:6
Stack trace:
#0 D:\test.php(9): include()
#1 {main}
thrown in D:\scheduler.php on line 6
Fatal error: Uncaught Error: Class 'GO\Scheduler' not found in D:\scheduler.php:6
Stack trace:
#0 D:\test.php(9): include()
#1 {main}
thrown in D:\scheduler.php on line 6
Hi,
is any way to use AND for simple expression (against using when()
method) while defining execution time for one Job?
For example (pseudo code):
$scheduler
->php(`some php script`)
->at('1 10 * * 1,2,3')
->at('1 8 * * 4,5')
I'm using your script inside a loop. So this is just the chunk that runs in the loop. The code uses Guzzle to hit a URL.
Currently, it sends an email every time a job is run. But, I'm trying to figure out how to only send email if Guzzle gives any status code other than 200... or maybe there is a better way?
$scheduler->call(function() use ($siteUrl, $file, $k, $v) {
$client = new \GuzzleHttp\Client();
$res = $client->head($siteUrl . $v['url'], [ 'http_errors' => false ]);
$data = [
'status' => $res->getStatusCode(),
'datetime' => date('Y-m-d H:i:s'),
];
echo json_encode($data);
})
->at($v['runtime'])
->output($file)
->configure([
'email' => [
'subject' => "Cron: '{$k}' at {$siteName}",
'from' => $config['email']['from'],
'transport' => $transport,
]
])
->email([ $toEmail ]);
Any ideas on how to set $toEmail
to false
inside the anonymous function ... or not send the email?
Thanks.
I was following this example
$scheduler->php('script.php')->then(function ($output) {
log('Job executed!');
}, true);
and I got Warning: log() expects parameter 1 to be float, string given
Hi there,
I'm reading a list of cronjobs from the database but I'm not sure how to use resetRun():
$listCron = $db->query(bla bla bla)
while {
$scheduler->php($file)->at($schedule);
$scheduler->resetRun()->run();
}
or maybe:
while {
$scheduler->php($file)->at($schedule);
}
$scheduler->run();
Many thanks,
Hey there,
Is it possible to run a job at a precise datetime, please ? I would like to use my scheduler for deferred production deployment.
Many thanks
There are some jobs I would like to schedule every x minutes.
I figured I could do it with ->everyMinute(5)
or maybe ->hourly('*/5')
but both aren't supported.
The latter could work if validateCronRange()
is fixed to support it.
For now I use this workaround: ->at('*/5 * * * *')
. But it is ugly, and kind of defeats the purpose of using an interface for scheduling.
I would think this is a common enough usage to be supported by the interface.
Im trying to use following code but it never worked for me. Is it possible to you help me to find my problem in this code ?
<?php
require_once __DIR__.'/vendor/autoload.php';
use GO\Scheduler;
$scheduler = new Scheduler();
$scheduler->php('test.php')->everyMinute();
$scheduler->run();
?>
It seems this is running tasks on the background to achieve parallelism. But does it work with windows?
Hi
Is it possible to change the email subject per schedule?
thanks
The after method is not available for access by php
using "peppeocchi/php-cron-scheduler": "^2.0"
$scheduler->php('script.php')->after(function ($output) use ($logger, $messenger) {
$logger->info($output);
$messenger->ping('myurl.com', $output);
});
I use the scheduler to run error reporting cron jobs. It means an output is generated only if there's an error and only then an email should be sent.
Could you add a setting/property/method which skips sending an email when there's no output given?
Hey, thanks for the effort.
Was wondering if the scheduler supports running php files asynchronously?
As far as I understood, it is waiting for a job to finish and then moves on to the next one,
So if I have set 10 crawlers to run every minute, it will timeout on first one that takes a minute.
Thanks again
Currently when passing an invalid path for a job to the scheduler (php only), it is throwing an InvalidArgumentException
straight away.
It would be a nice to have to instead of throwing the exception (and preventing other valid jobs to run) it will mark it as failed job and it will keep running the other jobs.
This is something already covered when scheduling Closures, so it should be handled only when scheduling php
scripts.
I have a job that takes 10 secs before it finishes. When I call ->then(function ($output)
that function is called immediately and not after the job has finished 10 secs later.
The first thing I do in the ->then(function ($output)
function is write the time and it's always something like 2017-10-03 07:14:00
, not 2017-10-03 07:14:10
Also, my job produces stdout but $output
is always null.
Greetings,
I've been turning this problem sideways for the last few hours and hope someone can point out the obvious to me.
Overall, the scheduler works fine. However, I cannot seem to get emails to be sent. Here is my script, which I know is being executed since it's running the scheduled PHP script. I've also tested out the Swift_SmtpTransport (which is why it's abstracted out below), which does send out email successfully using the same parameters.
Any advice would be appreciated. Cheers!
JP
require_once __DIR__.'/vendor/autoload.php';
use GO\Scheduler;
// Create the Transport the call setUsername() and setPassword()
$transport = (new Swift_SmtpTransport('mail.***.com', 789, 'ssl'))
->setUsername('scheduler@***.com')
->setPassword('***');
$scheduler = new Scheduler([
'email' => [
'subject' => 'croncron',
'from' => 'scheduler@***.com',
'body' => 'This is the email body',
'transport' => $transport
]
]);
// ... configure the scheduled jobs (see below) ...
$scheduler->php(
'/absolute/path-to-script.php', // The script to execute
'/usr/local/bin/php', // The PHP bin
[
'--account' => '1'
],
'IdScheduler'
)
->everyMinute()
->email(['***@***.com']);
// Let the scheduler execute jobs which are due.
$scheduler->run();
to many shared hosting provider disabled exec and shel_exec function , can i run it without use exec function ?
I think it's swift message, could you add SMTP settings on config ?
I couldn't get a script run at a specified date..
This is my code... it is not executing at the date specified it is rather executing instantly.. please help me.
$datetorun = new DateTime('2018-09-04 18:48:00');
$scheduler = new Scheduler();
$scheduler->php($pathtophpscripttorun, '/usr/local/bin/php')->run($datetorun);
what am i doing run.. please help.. i want the skip to run at the date specified.
I need to create a task that runs every day between a time interval, for example
Wheels every day every 5 minutes only between 20:00 to 07:00
Hello @peppeocchi.
Nice tool! Anyway, on my implementation requires to get the PID from the job execution. My approach was from http://php.net/manual/en/function.exec.php#88704.
For a while, I have forked your repo YucaApp@7ad0801. I'm happy to create a PR for that if you think that is good for other users to use it, or probably you have a better approach for this?
Thanks.
composer require peppeocchi/php-cron-scheduler:^2.3
$scheduler = new \GO\Scheduler()
$scheduler->call(
function($args) {
echo $args["foo"];
},
["foo" => "bar"],
"ident"
)->everyMinute();
$scheduler->run();
Within the closure, and based on the docs, I expect $args
to be an array and for $args["foo"]
to equal "bar"
.
However, that actual value of $args
is a string that equals "bar"
.
call_user_func_array($fn, $args)
to call_user_func($fn, $args)
Hi, Does this support javascript or jquery in php file
Thanks
Siba
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.