neogen/command-scheduler
Schedule and manage Laravel Artisan commands dynamically without touching your console kernel. Define commands, intervals, and arguments in config or the database, then let the scheduler run and track them automatically.
Before anything else: this is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/*.php file that Laravel's container will auto-discover. You will be manually wiring it or wrapping it.
composer.json (check the symfony/* version constraints — this tells you immediately whether it will even install alongside a modern Laravel), src/DependencyInjection/*Extension.php (the real config schema), src/Command/* (what actually executes), and any Resources/config/services.xml (how services are constructed and what they depend on).composer require neogen/command-scheduler. Expect a conflict wall. If it pins symfony/console:^3.4|^4.0, Composer will refuse to install it beside a current Laravel (which requires Symfony 6/7 components). You may need --ignore-platform-reqs plus a fork, or to vendor the source into app/Support/CommandScheduler.Application in isolation from a scheduled Artisan command. Create app/Console/Commands/RunNeogenSchedule.php whose handle() boots a bare Symfony Application, registers the bundle's commands, and invokes them. Then schedule that one command in routes/console.php. This keeps the bundle's DB-monitoring logic intact while letting Laravel own the cron entrypoint.php artisan tinker → confirm the classes autoload, then check the bundle's migration/schema requirements (if it tracks executions, it needs a table — and it will ship a Doctrine migration, not a Laravel one).Realistically, evaluate this for 30 minutes and then decide whether the monitoring value justifies the glue. For most Laravel apps it does not — see the alternatives in the last section.
Pattern 1 — Bare Symfony Application bridge (most viable).
Wrap the bundle inside a single Artisan command. Build a Symfony\Component\Console\Application, register the bundle's command classes by hand, set the input, and return the exit code. Because you control the Application, you sidestep Symfony's kernel/bundle boot entirely — you only need the command classes and whatever services they touch. Inject those services manually from Laravel's container.
Pattern 2 — Cron wrapper with history table.
If the bundle's value is the execution log, skip its scheduler and use only its model/repository. Migrate the schema with a hand-written Laravel migration mirroring the Doctrine entity, then write your own CommandRun Eloquent model against the same table. You get the monitoring data without the Symfony plumbing.
Pattern 3 — Laravel scheduler as orchestrator, package as recorder.
Keep Schedule::command(...)->everyFiveMinutes() doing the actual dispatch, and record start/finish/exit-code rows around each invocation using the package's column shape. This gives you a clean upgrade path: today it writes to the package's table, tomorrow you swap in spatie/laravel-schedule-monitor without touching call sites.
Pattern 4 — Isolated subprocess.
Shell out: Process::run('php bin/console neogen:run --quiet'). Ugly, but it is the only pattern guaranteed to work regardless of framework-version drift, and it isolates a 2018-era dependency from your app's autoloader and PHP version.
Integration tips
->withoutOverlapping() and ->onOneServer() in Laravel's scheduler so the bundle's own lock (if any) is a second line of defence, not the first."repositories" with a VCS entry in composer.json) rather than committing into vendor/, and pin the commit hash.createMock, each() on collections, or nullable-typehint syntax that breaks on PHP 8. Check for each(), dynamic properties, and ReflectionParameter::getClass() before committing.ContainerAwareCommand (removed in Symfony 5) and bundle registration via AppKernel. Neither exists in a Laravel app. Anything extending ContainerAwareCommand must be rewritten or booted inside a real Symfony kernel.->scalarNode('...'), ->arrayNode('...')). Read it rather than guessing key names from the README — the README is from 2018 and likely lags the code.datetime vs timestamp defaults and for indexes on the "last run" column that your monitoring queries will depend on.withoutOverlapping() at the Laravel scheduler layer regardless.php artisan about tells you nothing. Debug by instantiating the command class directly in tinker and calling execute() with an ArrayInput. Errors surface as raw Symfony exceptions with no Laravel context — wrap the bridge in try/catch and log with report().handle(), and emit your own Laravel events around the call.withoutOverlapping(), onOneServer(), runInBackground(), before()/after()/onSuccess()/onFailure() hooks, and Schedule::command()->emailOutputOnFailure(). For the monitoring half, spatie/laravel-schedule-monitor is maintained, first-class Laravel, and stores run history. This package solves a problem Laravel solved in the box — the only reason to adopt it is if you are porting an existing Symfony app and want to preserve its operational behaviour verbatim.How can I help you explore Laravel packages today?