Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jobby Laravel Package

hellogerard/jobby

Jobby is a PHP cron job manager that runs multiple scheduled jobs from one crontab entry, with built-in locking to prevent overlapping runs, logging, error email notifications, and per-job configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Jobby's job is narrow: it turns one crontab entry into a config-driven scheduler. Get those two pieces wired and you're productive immediately.

  1. Install: composer require hellogerard/jobby.
  2. Describe your jobs in a config file. Either a PHP file returning an array, or an INI file. PHP is usually the better default for a Laravel-adjacent codebase because you can read env vars and call functions:
<?php
// config/jobs.php
return [
    'nightly-report' => [
        'command'  => 'php /var/www/app/artisan reports:nightly',
        'schedule' => '0 2 * * *',
        'output'   => '/var/log/app/nightly-report.log',
    ],
    'cache-warm' => [
        'command'  => 'php /var/www/app/artisan cache:warm',
        'schedule' => '*/15 * * * *',
        'enabled'  => true,
    ],
];
  1. Add exactly one crontab line for the user that should own scheduling:
* * * * * cd /var/www/app && php vendor/bin/jobby -c config/jobs.php >/dev/null 2>&1

(If your install doesn't expose vendor/bin/jobby, the package also supports the programmatic form: a small executable that does new Jobby(); $jobby->add(...); $jobby->run();. Same idea, one entrypoint.)

  1. Verify it's alive before trusting it: check the output log file after a run, and run the entrypoint manually as the same user. Jobby only runs jobs whose cron expression matches the current minute, so a * * * * * job is the fastest way to confirm end-to-end behaviour.

First real use case: replace an existing bare crontab line (nightly report, cache warm, queue prune) with a Jobby entry. You immediately gain a log file, overlap protection, and a single place to look when "did the cron run?" comes up. Once one job is migrated, migrating the rest is copy-paste.

If you're on a modern Laravel app, note the obvious: schedule:run already does most of this. Jobby earns its keep when you have non-Laravel PHP, a mixed fleet of shell + PHP jobs, need per-job OS user switching, or want email alerts without building them.

Implementation Patterns

Config-as-code with env awareness. Return the array from jobs.php and build it with env()/getenv() so enabled, maxRuntime, and output paths differ per environment without editing cron. Keep the file in version control and deploy it with the app.

return [
    'sync-orders' => [
        'command'    => 'php /var/www/app/artisan orders:sync',
        'schedule'   => '*/5 * * * *',
        'output'     => '/var/log/app/sync-orders.log',
        'maxRuntime' => 240,
        'enabled'    => getenv('APP_ENV') !== 'local',
        'description'=> 'Pull new orders from the ERP',
    ],
];

Multiple schedules per job. schedule accepts an array, which beats duplicating a job just to run it twice a day:

'schedule' => ['0 8 * * *', '0 18 * * *'],

Wrap artisan, don't reimplement it. For Laravel apps the clean pattern is: write a console command that does the work and can be run interactively, then register it in Jobby as a one-liner command. You keep testability via php artisan my:command, and Jobby only handles scheduling concerns.

Use callables for tiny in-process tasks. If a job is a few lines of PHP (pruning a temp dir, busting a cache), a closure avoids shelling out:

'flush-tmp' => [
    'command'  => function () { /* ... */ },
    'schedule' => '0 3 * * *',
],

Keep them small — a callable runs inside the same PHP process as the Jobby tick, so memory and long runtimes affect everything else in that tick.

Per-job environment. Set environment on a job to scope env vars (e.g. APP_ENV, queue names), rather than exporting them globally in the crontab.

User switching. For jobs that must run as a different OS user (e.g. www-data for file ownership reasons), set user on that job and run the Jobby cron entry as root or via a narrowly-scoped sudo rule. Keep the number of root-run jobs as small as possible.

Toggle without redeploys. Because enabled is read from config, you can flip a job off by editing the deployed config, or by env var if you built it in. Prefer env for anything ops needs to touch at 3am.

Integration with monitoring. Jobby's output files are your ground truth. Tail them, or ship them to your log pipeline, and alert on "no new lines in N hours" rather than relying on cron alone — cron dying is silent.

Gotchas and Tips

  • You still need cron. Jobby is a scheduler that runs on top of cron; if cron/crond stops, every job stops. Add a heartbeat check.
  • The tick must finish within a minute. The * * * * * entry launches Jobby every minute. A job that runs long is protected by the per-job lock, but a pathological config can make ticks pile up. Use maxRuntime to bound runaway jobs and keep heavy work in separate entries if needed.
  • Overlap protection is keyed by job name. Renaming a job gives it a new lock identity, so a still-running old job and the renamed one can overlap in the split second around a deploy. Rename deliberately.
  • Use absolute paths. Cron's PATH is minimal. php may not be the same binary the shell resolved for you. Prefer /usr/bin/php8.2, and set any required env explicitly.
  • Timezone is the server's. Jobby's cron matching uses the process timezone; there's no per-job timezone option. Set date.timezone (or TZ) consistently and remember DST transitions can produce skipped/duplicated runs on hourly-style schedules.
  • Email alerts depend on the host MTA. Jobby's mail path is only as good as mail()/sendmail on the box. If deliverability matters, log to files and forward with a real alerting system; don't make email your only signal.
  • Output file permissions bite. If the cron user and the web user differ, log files can end up unreadable by the app or unwritable after rotation. Create log directories with correct ownership and add a logrotate rule.
  • Cron swallows stderr when you redirect to /dev/null. That's intentional in the recommended crontab line — just make sure every job has an output path so failures actually land somewhere.
  • Callables are not free. A closure that leaks memory or throws will affect the rest of that tick. Wrap risky bodies in try/catch and prefer a dedicated artisan/console command for anything substantial.
  • Debugging: run the entrypoint by hand as the cron user (sudo -u www-data php vendor/bin/jobby -c ...), and if the tool offers a debug/foreground flag and a "run just this job" filter, use them — don't debug by waiting for the next scheduled window.
  • Package age. Last release was 2020. Confirm PHP 8 compatibility on your target runtime before adopting, and pin the version in composer.json. It's a small, low-churn package, but it's not actively maintained, so treat upgrades of PHP as a reason to re-test it.
  • Don't double-schedule. If a job also exists in app/Console/Kernel.php (or the newer routes/console.php) or in the crontab, you'll get silent duplicates. Jobby should be the only scheduler for jobs it owns.
  • Extension point: for anything Jobby doesn't cover (e.g. custom notifications, metrics), keep it out of the config file and put it in the command itself — that keeps the scheduler declarative and the logic testable.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console