marios88 / jobbyng
Manage all your cron jobs without modifying crontab on PHP >=8.2. Handles locking, logging, and more.
Requires
- php: >=8.2
- dragonmantank/cron-expression: ^3.4
- opis/closure: ^4.0.1
- symfony/process: ^5.4|^6.4|^7.4|^8.0
Requires (Dev)
- phpunit/phpunit: ^10.5
- symfony/filesystem: ^5.4|^6.4|^7.4|^8.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-25 19:18:36 UTC
README
Install the master JobbyNG cron job, and it will manage all your offline tasks. Add jobs without modifying crontab. JobbyNG can handle logging, locking, and custom error notifications.
JobbyNG is the v5 continuation of Jobby. It uses the JobbyNg\ PHP namespace
and the marios88/jobbyng Composer package, so it can be installed alongside the
original hellogerard/jobby package during migration.
Features
- Maintain one master crontab job.
- Jobs run via PHP, so you can run them under any programmatic conditions.
- Use ordinary crontab schedule syntax (powered by the excellent
cron-expression). - Run only one copy of a job at a given time.
- Call an overridable notification hook whenever a job exits with an error status.
- Run job as another user, if crontab user has
sudoprivileges. - Run only on certain hostnames (handy in webfarms).
- Theoretical Windows support (but not ever tested)
Getting Started
Installation
The recommended way to install JobbyNG is through Composer:
$ composer require marios88/jobbyng
JobbyNG requires PHP 8.2 or newer.
Then add the following line to your (or whomever's) crontab:
* * * * * cd /path/to/project && php jobby.php 1>> /dev/null 2>&1
After JobbyNG installs, you can copy an example file to the project root.
$ cp vendor/marios88/jobbyng/resources/jobby.php .
Migrating from Jobby v4
JobbyNG uses a separate package and PHP namespace, so both versions can be installed while an application is migrated:
$ composer require hellogerard/jobby marios88/jobbyng
Update application imports from Jobby\ to JobbyNg\, for example:
use JobbyNg\Jobby; $jobby = new Jobby();
Running a job
<?php // Ensure you have included composer's autoloader require_once __DIR__ . '/vendor/autoload.php'; // Create a new instance of Jobby $jobby = new \JobbyNg\Jobby(); // Every job has a name $jobby->add('CommandExample', [ // Run a shell command 'command' => 'ls', // Ordinary crontab schedule format is supported. // This schedule runs every hour. 'schedule' => '0 * * * *', ]); $jobby->run();
Examples
Logging
<?php /* ... */ $jobby->add('LoggingExample', [ 'command' => 'ls', 'schedule' => '0 * * * *', // Stdout and stderr is sent to the specified file 'output' => 'logs/command.log', ]); /* ... */
Disabling a command
<?php /* ... */ $jobby->add('DisabledExample', [ 'command' => 'ls', 'schedule' => '0 * * * *', // You can turn off a job by setting 'enabled' to false 'enabled' => false, ]); /* ... */
Running closures
Closures are serialized and run in a separate process, so capture any values they need explicitly.
<?php /* ... */ $jobby->add('ClosureCommandExample', [ // Use the 'closure' key // instead of 'command' 'closure' => function() { echo "I'm a function!\n"; return true; }, 'schedule' => '0 * * * *', ]); /* ... */
Using a DateTime
<?php /* ... */ $jobby->add('DateTimeExample', [ 'command' => 'ls', // Use a DateTime string in // the format Y-m-d H:i:s // Replace this with the date and time when the job should run 'schedule' => '2030-05-03 17:15:00', ]); /* ... */
Using a Custom Scheduler
<?php /* ... */ $jobby->add('Example', [ 'command' => 'ls', // Use any callable that returns // a boolean stating whether // to run the job or not 'schedule' => function(DateTimeImmutable $now) { // Run on even minutes return $now->format('i') % 2 === 0; }, ]); /* ... */
Custom error notifications
Jobby does not send email by default. When a job has non-empty recipients, the
worker calls Helper::sendMail(), whose default implementation is a harmless
no-op. The legacy mail configuration keys remain available to custom helpers,
but are ignored by the default implementation.
Override the hook in an autoloadable Helper subclass, then inject that helper
from an autoloadable BackgroundJob subclass:
<?php namespace App\JobbyNg; class NotificationHelper extends \JobbyNg\Helper { public function sendMail($job, array $config, $message) { // Send the notification with your application's mailer. } }
<?php namespace App\JobbyNg; class CustomBackgroundJob extends \JobbyNg\BackgroundJob { public function __construct($job, array $config) { parent::__construct($job, $config, new NotificationHelper()); } }
Select the custom job class in the application configuration:
$jobby = new \JobbyNg\Jobby([ 'jobClass' => \App\JobbyNg\CustomBackgroundJob::class, ]);
Workers run in a separate PHP process, so injecting a helper into the parent
JobbyNg instance alone does not configure the worker. The jobClass route makes
the helper available after the worker loads Composer's autoloader. The default
Helper no longer accepts constructor-based SwiftMailer injection or returns a
Swift message.
Supported Options
Each job requires these:
| Key | Type | Description |
|---|---|---|
| schedule | string|callable | Crontab schedule format (man -s 5 crontab) or DateTime format (Y-m-d H:i:s) or callable (function(DateTimeImmutable $now): bool { /* ... */ }) |
| command | string | The shell command to run (exclusive-or with closure) |
| closure | Closure | The anonymous PHP function to run (exclusive-or with command) |
The options listed below can be applied to an individual job or globally through the Jobby constructor.
Global options will be used as default values, and individual jobs can override them.
| Option | Type | Default | Description |
|---|---|---|---|
| runAs | string | null | Run as this user, if crontab user has sudo privileges |
| debug | boolean | false | Send jobby internal messages to 'debug.log' |
| Filtering | Options to determine whether the job should run or not | ||
| environment | string | null or $_SERVER['APPLICATION_ENV'] |
Development environment for this job |
| runOnHost | string | php_uname('n') |
Run jobs only on this hostname |
| maxRuntime | integer | null | Maximum execution time for this job (in seconds) |
| enabled | boolean | true | Run this job at scheduled times |
| haltDir | string | null | A job will not run if this directory contains a file bearing the job's name |
| Logging | Options for logging | ||
| output | string | null | Redirect stdout and stderr to this file; uses the system null device when unset |
| output_stdout | string | value from output option |
Redirect stdout to this file |
| output_stderr | string | value from output option |
Redirect stderr to this file |
| dateFormat | string | Y-m-d H:i:s | Format for dates on jobby log messages |
| Error notification hook | Configuration passed to Helper::sendMail() |
||
| recipients | string | null | Comma-separated recipients; an empty value skips the hook |
| mailer | string | sendmail | Retained for custom helpers; ignored by the default hook |
| smtpHost | string | null | Available to custom helpers; ignored by the default hook |
| smtpPort | integer | 25 | Available to custom helpers; ignored by the default hook |
| smtpUsername | string | null | Available to custom helpers; ignored by the default hook |
| smtpPassword | string | null | Available to custom helpers; ignored by the default hook |
| smtpSecurity | string | null | Available to custom helpers; ignored by the default hook |
| smtpSender | string | jobby@<hostname> | Available to custom helpers; ignored by the default hook |
| smtpSenderName | string | jobby | Available to custom helpers; ignored by the default hook |
Credits
Developed before, but since inspired by whenever.
This project is maintained as marios88/jobbyng, based on jobbyphp/jobby. Support the creator of the original project here
AI Disclaimer
This project and its documentation may include content generated or assisted by AI tools. Review and verify AI-assisted changes before relying on them in production.