{"id":22290677,"url":"https://github.com/xfra35/f3-cron","last_synced_at":"2025-04-07T16:18:06.178Z","repository":{"id":32253250,"uuid":"35827604","full_name":"xfra35/f3-cron","owner":"xfra35","description":"Job scheduling for the PHP Fat-Free Framework","archived":false,"fork":false,"pushed_at":"2024-03-06T12:34:33.000Z","size":73,"stargazers_count":73,"open_issues_count":4,"forks_count":22,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-31T13:18:50.887Z","etag":null,"topics":["cron","fat-free-framework","job-scheduler","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xfra35.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-05-18T15:59:08.000Z","updated_at":"2025-03-17T15:32:33.000Z","dependencies_parsed_at":"2024-06-18T22:53:36.295Z","dependency_job_id":null,"html_url":"https://github.com/xfra35/f3-cron","commit_stats":{"total_commits":33,"total_committers":2,"mean_commits":16.5,"dds":"0.030303030303030276","last_synced_commit":"161da4d136f0a2a27c5f99a99ee738b9cafbd19b"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfra35%2Ff3-cron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfra35%2Ff3-cron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfra35%2Ff3-cron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xfra35%2Ff3-cron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xfra35","download_url":"https://codeload.github.com/xfra35/f3-cron/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247685628,"owners_count":20979085,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cron","fat-free-framework","job-scheduler","php"],"created_at":"2024-12-03T17:13:45.618Z","updated_at":"2025-04-07T16:18:06.151Z","avatar_url":"https://github.com/xfra35.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cron\n**Job scheduling for the PHP Fat-Free Framework**\n\nThis plugin for [Fat-Free Framework](http://github.com/bcosca/fatfree) helps you control job scheduling directly from your web app.\n\n* [Installation](#installation)\n* [Operation and basic usage](#operation-and-basic-usage)\n* [Schedule format](#schedule-format)\n    * [Crontab](#crontab)\n    * [Examples](#examples)\n    * [Presets](#presets)\n* [Options](#options)\n    * [Logging](#logging)\n    * [Web interface](#web-interface)\n    * [Script path](#script-path)\n    * [PHP binary path](#php-binary-path)\n* [Ini configuration](#ini-configuration)\n* [Asynchronicity](#asynchronicity)\n* [Common pitfalls](#common-pitfalls)\n    * [UNIX user permissions](#unix-user-permissions)\n    * [Overlapping jobs](#overlapping-jobs)\n* [API](#api)\n\n## Installation\n\nTo install this plugin, just copy the `lib/cron.php` file into your `lib/` or your `AUTOLOAD` folder.\n\n## Operation and basic usage\n\nThis plugin provides your app with an external interface to run scheduled jobs.\nThe interface consists in 2 routes automatically added to your app:\n\n* `GET /cron` checks for due jobs and executes them\n* `GET /cron/@job` triggers a specific job\n\nBy default, this interface is accessible in CLI mode only and is meant to be called by the server job scheduler:\n\n1. Unix cron or Windows Task Scheduler calls `index.php /cron` every minute (or at a slower rate).\n2. `index.php /cron` checks for due jobs at that time and executes them, asynchronously if possible.\n\n### Step 1:\n\nConfigure your server job scheduler so that it calls `php index.php /cron` every minute.\n\nHere's how to do it on a \\*nix server, assuming that your application resides in `/path/to/app/index.php`:\n\n* create a file named, for example, *mycrontab*, containing the following line:\n\n```cron\n* * * * * cd /path/to/app; php index.php /cron\n```\n\n* configure cron with it, using the following command:\n\n```bash\ncrontab mycrontab\n```\n\n**NB1:** depending on your hosting, you may need to ask your provider to perform that step.\n\n**NB2:** if your cron job needs disk write access, take care about the [UNIX user permissions](#unix-user-permissions).\n\n### Step 2:\n\nInstantiate the `Cron` class and define the list and frequency of jobs with the following commands:\n\n```php\n//index.php\n$f3=require('lib/base.php');\n...\n$cron=Cron::instance();\n$cron-\u003eset('Job1','App-\u003ejob1','@daily');\n$cron-\u003eset('Job2','App-\u003ejob2','@weekly');\n...\n$f3-\u003erun();\n```\n\n### That's it!\n\n*Job1* will run every day and *Job2* every week.\n\n\n## Schedule format\n\n### Crontab\n\nEach job is scheduled using the (nearly) standard crontab format,\nwhich consists of 5 fields separated by spaces:\n\n```\n * * * * *\n │ │ │ │ │\n │ │ │ │ │\n │ │ │ │ └───── day of week (0 - 6) (0 to 6 are Sunday to Saturday)\n │ │ │ └────────── month (1 - 12)\n │ │ └─────────────── day of month (1 - 31)\n │ └──────────────────── hour (0 - 23)\n └───────────────────────── min (0 - 59)\n```\n\nEach field may be:\n\n* a `*`, meaning *any* value\n* a number: `3`\n* a range: `1-4` (equals `1,2,3,4`)\n* a list of numbers or ranges: `1-4,6,8-10`\n\nRanges have a default step value of 1, which can be adjusted using a `/`:\n\n* `1-6/2` is the same as `1,3,5`\n* `*/3` is the same as `1,4,7,10` (month column)\n\n### Examples\n\n```php\n$cron-\u003eset('Job1','App-\u003ejob1','* * * * *'); // runs every minute\n$cron-\u003eset('Job2','App-\u003ejob2','*/5 * * * *'); // runs every 5 minutes\n$cron-\u003eset('Job3','App-\u003ejob3','0 8 * * 1'); // runs every Monday at 08:00\n$cron-\u003eset('Job4','App-\u003ejob4','0 4 10 * *'); // runs the 10th of each month at 04:00\n$cron-\u003eset('Job5','App-\u003ejob5','0 0 * */3 *'); // runs on a quarterly basis\n```\n\n### Presets\n\nFor easier reading, it is possible to define presets:\n\n```php\n$cron-\u003epreset('weekend','0 8 * * 6'); // runs every Saturday at 08:00\n$cron-\u003epreset('lunch','0 12 * * *'); // runs every day at 12:00\n$cron-\u003eset('Job6','App-\u003ejob6','@weekend');\n$cron-\u003eset('Job7','App-\u003ejob7','@lunch');\n```\n\nThe following presets are defined by default:\n\n* `@yearly` or `@annually` \u003c=\u003e `0 0 1 1 *`\n* `@monthly` \u003c=\u003e `0 0 1 * *`\n* `@weekly` \u003c=\u003e `0 0 * * 0`\n* `@daily` \u003c=\u003e `0 0 * * *`\n* `@hourly` \u003c=\u003e `0 * * * *`\n\n## Options\n\n### Logging\n\nIf you set `$cron-\u003elog=TRUE`, every successfully executed job will be logged in a `cron.log` file located in the [LOGS](http://fatfreeframework.com/quick-reference#LOGS) folder.\n\n### Web interface\n\nBy default, the routes `GET /cron` and `GET cron/@job` are available in CLI mode only, which means that an HTTP request to them will throw a 404 error.\n\nYou can enable web routes by setting `$cron-\u003eweb=TRUE`.\n\nIn that case, `/cron` can be triggered via HTTP on a periodic basis, for example by your web app, or by a web cron service, or even by your own crontab:\n\n```cron\n* * * * * curl http://mydomain.tld/cron\n```\n\n### Script path\n\nBy default, the script called asynchronously is `index.php` located in the current working directory.\n\nYou may need to tweak this value if:\n\n* your web root differs from your app root (e.g: `index.php` resides in `www/` and starts with `chdir('..')`)\n* all your scheduling is handled in a separate file (e.g: `cron.php` instead of `index.php`)\n\nExamples:\n\n```php\n$cron-\u003escript='htdocs/index.php';//relative to app root\n$cron-\u003escript=__DIR__.'/cron.php';//absolute path\n```\n\n### PHP binary path\n\nBy default, the PHP binary used to trigger asynchronous job executions is either `php` or `php-cli` (smart guess).\n\nYou may need to tweak this value if none of these values correspond to an executable PHP CLI binary\nor if they are not in the path.\n\nExample:\n\n```php\n$cron-\u003ebinary('/home/myphp-cli');\n```\n\nThe PHP binary validity is checked every time the class is instanciated, which can lead to a performance hit (see https://github.com/xfra35/f3-cron/issues/9).\n\nYou can skip this check by forcing the path, using the 2nd parameter:\n\n```php\n$cron-\u003ebinary('/home/myphp-cli',TRUE); // set PHP binary path, whether it's valid or not\n```\n\nIn that case, you are responsible for providing the correct path.\n\n## Ini configuration\n\nConfiguration is possible from within an .ini file, using the `CRON` variable. E.g:\n\n```ini\n[CRON]\nlog = TRUE\nweb = FALSE\nscript = /path/to/index.php\nbinary = /path/to/php\n\n[CRON.presets]\nlunch = 0 12 * * *\n\n[CRON.jobs]\nJob1 = App-\u003ejob1, * * * * *\nJob2 = App-\u003ejob2, @lunch\nJob3 = App-\u003ejob3, @hourly\n```\n\nIf you need to force the PHP binary path, just pass TRUE as a 2nd parameter:\n\n```ini\n[CRON]\nbinary = /path/to/php, TRUE\n```\n\n**IMPORTANT:** Don't forget to instantiate the class before running your app:\n\n```php\n//index.php\n$f3=require('lib/base.php')\n$f3-\u003econfig('cron.ini');\nCron::instance(); // \u003c--- MANDATORY\n$f3-\u003erun();\n```\n\n## Asynchronicity\n\nAs configured in [step 1](#step-1), the cron plugin is instantianted every minute. Each instance is run independantly from each other.\n\nWithin an instance, there may be several due jobs, which can be run synchronously or asynchronously.\n\nIf you want due jobs to be run asynchronously within an instance, you'll need:\n* `exec()` to be enabled on your hosting\n* the [script path](#script-path) to be configured correctly\n* the [PHP CLI binary](#php-binary-path) to be executable and in the path of your hosting user\n\n**NB:** The plugin will detect automatically if jobs can be run asynchronously.\nIf not, jobs will be executed synchronously, which may take longer and add a risk of queue loss in case of a job failure.\n\n## Common pitfalls\n\n### UNIX user permissions\n\nIf one of your cron jobs writes data to disk, you may face some permission issues if both the cron user and\nthe web server user try to write data to the same files.\n\nFor example, let's imagine that you cron job is executed as `root` and renders a HTML template to embed it in\na reporting email. Then the next time the web server will try to recompile this template, it will not be allowed\nto modify the temporary file located in `$f3-\u003eTEMP` and the web user will face a 500 error.\n\nSee [this issue](https://github.com/xfra35/f3-cron/issues/4) for another example.\n\nHere are two different ways to fix that kind of issue:\n\n* make sure your cron jobs are executed by the web server user, with `crontab -u www mycrontab` (where `www` is the name of the web server user)\n* make sure the web server user and the cron user belong to the same UNIX group and give group write access to the writeable folders\n(e.g `chmod -R g+w /srv/www/tmp`)\n\n### Overlapping jobs\n\nIf a job runs longer than what it was designed for, one instance may overlap another (e.g: a job running every 5 min that completes in 6 min).\n\nDepending on the type of job, this situation may be undesirable (risk of data corruption).\n\nIf that's the case, you should prevent jobs from overlapping by using one of the following solutions:\n\n#### Setting a max execution time\n\nThe [max execution time](http://php.net/manual/en/info.configuration.php#ini.max-execution-time) in CLI mode defaults to 0.\nThat means scripts can run forever.\n\nSetting that parameter to a value slightly smaller than the job frequency will prevent jobs from overlapping.\n\n**NB:** don't forget to send a report on job failure, otherwise you could end up with all jobs failing silently.\n\n#### Using a resource locking mechanism\n\nInside your application code, you could keep track of running jobs using a lock file or a database flag, so that two cron instances\ncan't execute the same job at the same time.\n\n**NB:** don't forget to handle stale locks.\n\nAlternatively, you can use the `flock` binary, which provides automatic lock management. Beware that this solution is slightly\ndifferent as it prevents two cron instances (not jobs) from executing at the same time: if \"job1\" is still running, \"job1\" *and* \"job2\"\nwill be skipped. This solution is easy to implement though: just replace the crontab defined in [step 1](#step-1) with the following one:\n\n```cron\n* * * * * cd /path/to/app; flock -n cron.lock php index.php /cron\n```\n\n**NB:** the `cron.lock` can be located anywhere, provided the `cron` has write access to it.\n\n## API\n\n```php\n$cron = Cron::instance();\n```\n\n### log\n\n**Logging of successfully executed jobs (default=FALSE)**\n\n```php\n$cron-\u003elog=TRUE;// enable logging\n```\n\n### web\n\n**Web interface (default=FALSE)**\n\n```php\n$cron-\u003eweb=TRUE;// enable web interface\n```\n\n### script\n\n**Path of the script to call asynchronously (default='index.php')**\n\nDefaults to `index.php` in the current working directory.\n\n```php\n$cron-\u003escript='htdocs/index.php';//relative to app root\n$cron-\u003escript=__DIR__.'/cron.php';//absolute path\n```\n\n### clipath\n\n**Alias for script [deprecated]**\n\n### binary\n\n**Path of the PHP CLI binary (default='php' or 'php-cli')**\n\n```php\necho $cron-\u003ebinary;// php\n```\n\n### binary( $path, $force=FALSE )\n\n**Set PHP CLI binary path if it's valid (which means if it can be executed and is CLI)**\n\nIf `$force=TRUE`, the path is forced without validation check. This option can be used for performance optimization (see https://github.com/xfra35/f3-cron/issues/9).\n\n```php\n$cron-\u003ebinary('/home/myphp-cli'); // set PHP binary path, only if it's valid\n$cron-\u003ebinary('/home/myphp-cli',TRUE); // set PHP binary path, whether it's valid or not\n```\n\n### silent\n\n**Silent mode (default=TRUE)**\n\nDisable silent mode if you want the script to output the list of executed jobs.\n\n```php\n$cron-\u003esilent=FALSE;\n```\n\n### set( $job, $handler, $expr )\n\n**Schedule a job**\n\n```php\n$cron-\u003eset('Job1','App-\u003ejob1','@daily'); // runs daily\n$cron-\u003eset('Job2','App-\u003ejob2','*/5 * * * *'); // runs every 5 minutes\n$cron-\u003eset('Job3','App-\u003ejob3','0 8 * * 1'); // runs every Monday at 08:00\n```\n\n**NB:** Valid characters for job names are alphanumeric characters and hyphens.\n\n### preset( $name, $expr )\n\n**Define a schedule preset**\n\n```php\n$cron-\u003epreset('weekend','0 8 * * 6'); // runs every Saturday at 08:00\n$cron-\u003epreset('lunch','0 12 * * *'); // runs every day at 12:00\n```\n\n**NB:** Valid characters for job names are alphanumeric characters.\n\n### isDue( $job, $time )\n\n**Returns TRUE if the requested job is due at the given time**\n\n```php\n$cron-\u003eisDue('Job3',time()); // returns TRUE if Job3 is due now\n```\n\n### execute( $job, $async=TRUE )\n\n**Execute a job**\n\n```php\n$cron-\u003eexecute('Job2',FALSE); // executes Job2 synchronously\n```\n\n### run( $time=NULL, $async=TRUE )\n\n**Run scheduler, i.e executes all due jobs at a given time**\n\n```php\n$cron-\u003erun(strtotime('yesterday midnight'));\n// run asynchronously all jobs due yesterday at midnight\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxfra35%2Ff3-cron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxfra35%2Ff3-cron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxfra35%2Ff3-cron/lists"}