yalesov / zf2-cron
ZF2 cron module
Installs: 673
Dependents: 2
Suggesters: 0
Security: 0
Stars: 59
Watchers: 9
Forks: 16
Open Issues: 4
Requires
- php: >=5.3.3
- yalesov/arg-validator: 2.*
- yalesov/background-exec: 2.*
- yalesov/cron-expr-parser: 2.*
- yalesov/yaml: 2.*
- yalesov/zf2-doctrine: 2.*
- zendframework/zendframework: 2.*
Requires (Dev)
README
ZF2 cron module
This module serves as a central cron runner. It allows you to register a cron job in your ZF2 app; these jobs will be aggregated and run together. This allows you to maintain only a single entry in your crontab, while maintaining as many cron jobs as needed in the ZF2 app.
Installation
{ "require": { "yalesov/zf2-cron": "3.*" } }
Then add Yalesov\Cron
to the modules
key in (app root)/config/application.config.*
Cron module will also hook onto your application's database, through DoctrineORMModule
. It will create a single table, he_cron_job
, and will use the default EntityManager doctrine.entitymanager.orm_default
. If your settings are different, please modify the doctrine
section of config/module.config.yml
and instances of doctrine.entitymanager.orm_default
in Yalesov\Cron\Controller\CronController
as needed.
Finally, you need to update your database schema. The recommended way is through Doctrine's CLI:
$ vendor/bin/doctrine-module orm:schema-tool:update --force
Features
- All standard cron features (within PHP)
- Extended cron expression to support more complex use cases
- Centralized cron entry point / runner - you only need to maintain one entry in your crontab
- Cron job registration at runtime - you can, for example, register conditional cron jobs
- Cron job identifiers - allow for later modification of cron jobs
- Cron job lock - prevent a single job from being executed multiple times
- Unresponsive script recovery - recover long-running cron jobs and re-queue them automatically
- Logging - All jobs, whether
success
,running
,missed
, orerror
, will be logged; error messages and stack traces are also logged forerror
andmissed
cron jobs.
Config
Copy config/cron.local.php.dist
to (app root)/config/autoload/cron.local.php
, and modify the settings.
scheduleAhead
: how long ahead to schedule cron jobs. Cron jobs must be scheduled into individual jobs before they can be run, in order to keep track of individual cron job locks, logs, and recovery from individual long-running scripts.scheduleLifetime
: how long before a scheduled job is considered missed. If a job is scheduled, but not run - e.g. the crontab entry is deleted - for longer thanscheduleLifetime
, it will be invalidated and marked asmissed
.maxRunningTime
: maximum running time of each cron job. If jobs are running for longer thanmaxRunningTime
, it will be recovered and re-queued for re-run.successLogLifetime
: how long to keep successfully completed cron job logsfailureLogLifetime
: how long to keep failed (missed
/error
) cron job logs
Usage
Add a cron job
Run Foo::runCron('bar', 'baz')
every 15 minutes, with the identifier foo
.
use Yalesov\Cron\Service\Cron; Cron::register( 'foo', '*/15 * * * *', 'Foo::runCron', array('bar', 'baz') );
Function signature:
public static function register($code, $frequency, $callback, array $args = array())
$code
is a unique identifier for the job. It allows for later job overwriting, retrieval of Jobs by identifier, filtering, etc.
$frequency
is any valid cron expression, in addition supporting:
- range:
0-5
- range + interval:
10-59/5
- comma-separated combinations of these:
1,4,7,10-20
- English months:
january
- English months (abbreviated to three letters):
jan
- English weekdays:
monday
- English weekdays (abbreviated to three letters):
mon
- These text counterparts can be used in all places where their numerical counterparts are allowed, e.g.
jan-jun/2
- A full example:
0-5,10-59/5 * 2-10,15-25 january-june/2 mon-fri
(every minute between minute 0-5 + every 5th minute between 10-59; every hour; every day between day 2-10 and day 15-25; every 2nd month between January-June; Monday-Friday)
$callback
is any valid PHP callback.
$args
(optional) are the arguments to the callback. The cron job will be called with call_user_func_array, so $args[0]
will be the first argument, $args[1]
the second, etc.
Run the cron jobs
In order to actually run the cron jobs, you will need to setup a (real) cron job to trigger the Cron module. It will then run your registered cron jobs at their specified frequencies, retrying and logging as specified.
Recommended: set up a cron job and run the ZF2 app through CLI:
$ php public/index.php cron
Fallback: if the above doesn't work, you can always run it through a browser (or through lynx, wget, etc)
http://(zf2 app)/cron
Security: this will not expose any of your cron data or error outputs to any end-user. The controller will immediately close the connection, send an empty response, and continue running the cron jobs as background.
Retrieving logs; advanced use cases
You can interact with individual cron jobs through the Doctrine 2 ORM API. The Cron module only defines a single Entity Yalesov\Cron\Entity\Job
:
id
: unique identifier for individual cron jobscode
: cron job "batch/family" identifier, as set inCron::register()
status
: one ofpending
,success
,running
,missed
, orerror
errorMsg
: stores the error message forerror
cron jobsstackTrace
: stores the stack trace forerror
cron jobscreateTime
: (datetime) time when this individual job is createdscheduleTime
: (datetime) time when this individual job is scheduled to be runexecuteTime
: (datetime) time when this job is run (start of execution)finishTime
: (datetime) time when this job has terminated. will benull
for jobs other thansuccess
.
Example: retrieve all error messages of the cron job foo
:
// $em instance of EntityManager $errorJobs = $em->getRepository('Yalesov\Cron\Entity\Job')->findBy(array( 'code' => 'foo', 'status' => \Yalesov\Cron\Repository\Job::STATUS_ERROR, )); foreach ($errorJobs as $job) { echo sprintf( "cron job, code %s, executed at %s with error \n %s \n\n", $job->getCode(), // will always be 'foo' in this example $job->getExecuteTime()->format('r'), $job->getErrorMsg() ); }